home *** CD-ROM | disk | FTP | other *** search
/ Aminet 45 / Aminet 45 (2001)(GTI - Schatztruhe)[!][Oct 2001].iso / Aminet / gfx / x11 / x3270_3_2_16.lha / amiga_src / screen.c < prev    next >
C/C++ Source or Header  |  2001-06-30  |  89KB  |  3,770 lines

  1. /*
  2.  * Modifications Copyright 1993, 1994, 1995, 1996, 1999, 2000 by Paul Mattes.
  3.  * Original X11 Port Copyright 1990 by Jeff Sparkes.
  4.  *  Permission to use, copy, modify, and distribute this software and its
  5.  *  documentation for any purpose and without fee is hereby granted,
  6.  *  provided that the above copyright notice appear in all copies and that
  7.  *  both that copyright notice and this permission notice appear in
  8.  *  supporting documentation.
  9.  *
  10.  * Copyright 1989 by Georgia Tech Research Corporation, Atlanta, GA 30332.
  11.  *  All Rights Reserved.  GTRC hereby grants public use of this software.
  12.  *  Derivative works based on this software must incorporate this copyright
  13.  *  notice.
  14.  */
  15.  
  16. /*
  17.  *    screen.c
  18.  *        This module handles the X display.  It has been extensively
  19.  *        optimized to minimize X drawing operations.
  20.  */
  21.  
  22. #include "globals.h"
  23. #include <X11/IntrinsicP.h>
  24. #include <X11/StringDefs.h>
  25. #include <X11/Xatom.h>
  26. #include <X11/Shell.h>
  27. #include <X11/Composite.h>
  28. #include <X11/Xaw/Dialog.h>
  29. #include <X11/Xaw/Scrollbar.h>
  30. #include "Husk.h"
  31. #include <X11/cursorfont.h>
  32. #include <X11/keysym.h>
  33. #include <errno.h>
  34. #include "3270ds.h"
  35. #include "appres.h"
  36. #include "screen.h"
  37. #include "ctlr.h"
  38. #include "cg.h"
  39. #include "resources.h"
  40.  
  41. #include "actionsc.h"
  42. #include "ansic.h"
  43. #include "charsetc.h"
  44. #include "ctlrc.h"
  45. #include "hostc.h"
  46. #include "keymapc.h"
  47. #include "keypadc.h"
  48. #include "kybdc.h"
  49. #include "menubarc.h"
  50. #include "popupsc.h"
  51. #include "savec.h"
  52. #include "screenc.h"
  53. #include "scrollc.h"
  54. #include "statusc.h"
  55. #include "tablesc.h"
  56. #include "trace_dsc.h"
  57. #include "utilc.h"
  58. #include "xioc.h"
  59.  
  60. #if defined(HAVE_SYS_SELECT_H) /*[*/
  61. #include <sys/select.h>        /* fd_set declaration */
  62. #endif /*]*/
  63.  
  64. #include "x3270.bm"
  65. #include "wait.bm"
  66.  
  67. #define SCROLLBAR_WIDTH    15
  68. /* #define _ST */
  69.  
  70. /* Externals: main.c */
  71. extern int      default_screen;
  72.  
  73. /* Externals: ctlr.c */
  74. extern Boolean  screen_changed;
  75. extern int      first_changed;
  76. extern int      last_changed;
  77.  
  78. /* Globals */
  79. unsigned char  *selected;    /* selection bitmap */
  80. Dimension       main_width;
  81. #include <X11/bitmaps/gray>
  82. Boolean         scrollbar_changed = False;
  83. Boolean         model_changed = False;
  84. Boolean        efont_changed = False;
  85. Boolean        oversize_changed = False;
  86. Boolean        scheme_changed = False;
  87. Pixel           keypadbg_pixel;
  88. Boolean         flipped = False;
  89. Pixmap          icon;
  90. Boolean        shifted = False;
  91. struct font_list *font_list = (struct font_list *) NULL;
  92. int             font_count = 0;
  93. char           *efontname;
  94.  
  95. /* Statics */
  96. static Dimension main_height;
  97. static union sp *temp_image;    /* temporary for X display */
  98. static Pixel    colorbg_pixel;
  99. static Boolean  cursor_displayed = False;
  100. static Boolean  cursor_enabled = True;
  101. static Boolean  cursor_blink_pending = False;
  102. static XtIntervalId cursor_blink_id;
  103. static int    field_colors[4];
  104. static Boolean  in_focus = False;
  105. static Boolean  line_changed = False;
  106. static Boolean  cursor_changed = False;
  107. static Boolean  iconic = False;
  108. static Widget   container;
  109. static Widget   scrollbar;
  110. static Dimension menubar_height;
  111. #if defined(X3270_KEYPAD) /*[*/
  112. static Dimension keypad_height;
  113. static Dimension keypad_xwidth;
  114. #endif /*]*/
  115. static Dimension container_width;
  116. static Dimension cwidth_nkp;
  117. static Dimension container_height;
  118. static Dimension scrollbar_width;
  119. static char    *aicon_text = CN;
  120. static XFontStruct *ailabel_font;
  121. static Dimension aicon_label_height = 0;
  122. static GC       ailabel_gc;
  123. static Pixel    cpx[16];
  124. static Boolean  cpx_done[16];
  125. static Pixel    normal_pixel;
  126. static Pixel    select_pixel;
  127. static Pixel    bold_pixel;
  128. static Pixel    selbg_pixel;
  129. static Pixel    cursor_pixel;
  130. static Boolean  text_blinking_on = True;
  131. static Boolean  text_blinkers_exist = False;
  132. static Boolean  text_blink_scheduled = False;
  133. static XtIntervalId text_blink_id;
  134. static XtTranslations screen_t00 = NULL;
  135. static XtTranslations screen_t0 = NULL;
  136. static XtTranslations container_t00 = NULL;
  137. static XtTranslations container_t0 = NULL;
  138. static unsigned char    *rt_buf8 = (unsigned char *) NULL;
  139. static XChar2b *rt_buf16 = (XChar2b *) NULL;
  140. static char    *color_name[16] = {
  141.     (char *)NULL, (char *)NULL, (char *)NULL, (char *)NULL,
  142.     (char *)NULL, (char *)NULL, (char *)NULL, (char *)NULL,
  143.     (char *)NULL, (char *)NULL, (char *)NULL, (char *)NULL,
  144.     (char *)NULL, (char *)NULL, (char *)NULL, (char *)NULL
  145. };
  146. static Boolean    configure_ticking = False;
  147. static XtIntervalId configure_id;
  148.  
  149. static Pixmap   inv_icon;
  150. static Pixmap   wait_icon;
  151. static Pixmap   inv_wait_icon;
  152. static Boolean  icon_inverted = False;
  153. static Widget    icon_shell;
  154.  
  155. static struct font_list *font_last = (struct font_list *) NULL;
  156.  
  157. /* Globals for undoing reconfigurations. */
  158. static enum {
  159.     REDO_NONE,
  160.     REDO_FONT,
  161. #if defined(X3270_MENUS) /*[*/
  162.     REDO_MODEL,
  163. #endif /*]*/
  164. #if defined(X3270_KEYPAD) /*[*/
  165.     REDO_KEYPAD,
  166. #endif /*]*/
  167.     REDO_SCROLLBAR,
  168.     REDO_RESIZE
  169. } screen_redo = REDO_NONE;
  170. static char *redo_old_font = CN;
  171. #if defined(X3270_MENUS) /*[*/
  172. static int redo_old_model;
  173. static int redo_old_ov_cols;
  174. static int redo_old_ov_rows;
  175. #endif /*]*/
  176.  
  177. static unsigned char blank_map[32];
  178. #define BKM_SET(n)    blank_map[(n)/8] |= 1 << ((n)%8)
  179. #define BKM_ISSET(n)    ((blank_map[(n)/8] & (1 << ((n)%8))) != 0)
  180.  
  181. enum fallback_color { FB_WHITE, FB_BLACK };
  182. static enum fallback_color ibm_fb = FB_WHITE;
  183.  
  184. /*
  185.  * The screen state structure.  This structure is swapped whenever we switch
  186.  * between normal and active-iconic states.
  187.  */
  188. #define NGCS    16
  189. struct sstate {
  190.     Widget          widget;    /* the widget */
  191.     Window          window;    /* the window */
  192.     union sp       *image;    /* what's on the X display */
  193.     int             cursor_daddr;    /* displayed cursor address */
  194.     Boolean         exposed_yet;    /* have we been exposed yet? */
  195.     Boolean         overstrike;    /* are we overstriking? */
  196.     Dimension       screen_width;    /* screen dimensions in pixels */
  197.     Dimension       screen_height;
  198.     GC              gc[NGCS * 2],    /* standard, inverted GCs */
  199.                     selgc[NGCS],    /* color selected text GCs */
  200.                     mcgc,    /* monochrome block cursor GC */
  201.                     ucgc,    /* unique-cursor-color cursor GC */
  202.                     invucgc;/* inverse ucgc */
  203.     int             char_height;
  204.     int             char_width;
  205.     Font        fid;
  206.     int        ascent;
  207.     int        descent;
  208.     Boolean         standard_font;
  209.     Boolean        extended_3270font;
  210.     Boolean         latin1_font;
  211.     Boolean         debugging_font;
  212.     Boolean         obscured;
  213.     Boolean         copied;
  214.     unsigned char  *xfmap;    /* standard font CG-to-ASCII map */
  215. };
  216. static struct sstate nss;
  217. static struct sstate iss;
  218. static struct sstate *ss = &nss;
  219.  
  220. /* Globals based on nss, used mostly by status and select routines. */
  221. Widget         *screen = &nss.widget;
  222. Window         *screen_window = &nss.window;
  223. int            *char_width = &nss.char_width;
  224. int            *char_height = &nss.char_height;
  225. int            *ascent = &nss.ascent;
  226. int            *descent = &nss.descent;
  227. Boolean        *standard_font = &nss.standard_font;
  228. Boolean        *latin1_font = &nss.latin1_font;
  229. Boolean        *debugging_font = &nss.debugging_font;
  230. Boolean        *extended_3270font = &nss.extended_3270font;
  231.  
  232. /* Mouse-cursor state */
  233. enum mcursor_state { LOCKED, NORMAL, WAIT };
  234. static enum mcursor_state mcursor_state = LOCKED;
  235. static enum mcursor_state icon_cstate = NORMAL;
  236.  
  237. static void aicon_init(void);
  238. static void aicon_reinit(unsigned cmask);
  239. static void screen_focus(Boolean in);
  240. static void make_gc_set(struct sstate *s, int i, Pixel fg, Pixel bg);
  241. static void make_gcs(struct sstate *s);
  242. static void put_cursor(int baddr, Boolean on);
  243. static void resync_display(union sp *buffer, int first, int last);
  244. static void draw_fields(union sp *buffer, int first, int last);
  245. static void render_text(union sp *buffer, int baddr, int len,
  246.     Boolean block_cursor, union sp *attrs);
  247. static void cursor_pos(void);
  248. static void cursor_on(void);
  249. static void schedule_cursor_blink(void);
  250. static void schedule_text_blink(void);
  251. static void inflate_screen(void);
  252. static int fa_color(unsigned char fa);
  253. static Boolean cursor_off(void);
  254. static void draw_aicon_label(void);
  255. static void set_mcursor(void);
  256. static void scrollbar_init(Boolean is_reset);
  257. static void init_rsfonts(void);
  258. static void allocate_pixels(void);
  259. static int fl_baddr(int baddr);
  260. static GC get_gc(struct sstate *s, int color);
  261. static GC get_selgc(struct sstate *s, int color);
  262. static void default_color_scheme(void);
  263. static Boolean xfer_color_scheme(char *cs, Boolean do_popup);
  264. static void set_font_globals(XFontStruct *f, const char *ef, Font ff);
  265. static void screen_connect(Boolean ignored);
  266. static void configure_stable(XtPointer closure, XtIntervalId *id);
  267. static void cancel_blink(void);
  268. static void render_blanks(int baddr, int height, union sp *buffer);
  269. static void resync_text(int baddr, int len, union sp *buffer);
  270. static void screen_reinit(unsigned cmask);
  271. static void aicon_font_init(void);
  272. static void aicon_size(Dimension *iw, Dimension *ih);
  273. static void invert_icon(Boolean inverted);
  274. static const char *load_fixed_font(const char *name);
  275. static void lock_icon(enum mcursor_state state);
  276.  
  277. /* Resize font list. */
  278. struct rsfont {
  279.     struct rsfont *next;
  280.     char *name;
  281.     int width;
  282.     int height;
  283.     int total_width;    /* transient */
  284.     int total_height;    /* transient */
  285.     int area;        /* transient */
  286. };
  287. static struct rsfont *rsfonts;
  288.  
  289. #define BASE_MASK        0x0f    /* mask for 16 actual colors */
  290. #define INVERT_MASK        0x10    /* toggle for inverted colors */
  291. #define GC_NONDEFAULT        0x20    /* distinguishes "color 0" from zeroed
  292.                         memory */
  293.  
  294. #define COLOR_MASK        (GC_NONDEFAULT | BASE_MASK)
  295. #define INVERT_COLOR(c)        ((c) ^ INVERT_MASK)
  296. #define NO_INVERT(c)        ((c) & ~INVERT_MASK)
  297.  
  298. #define DEFAULT_PIXEL        (appres.m3279 ? COLOR_BLUE : FA_INT_NORM_NSEL)
  299. #define PIXEL_INDEX(c)        ((c) & BASE_MASK)
  300.  
  301.  
  302. /*
  303.  * Save 00 event translations.
  304.  */
  305. void
  306. save_00translations(Widget w, XtTranslations *t00)
  307. {
  308.     *t00 = w->core.tm.translations;
  309. }
  310.  
  311. /* 
  312.  * Define our event translations
  313.  */
  314. void
  315. set_translations(Widget w, XtTranslations *t00, XtTranslations *t0)
  316. {
  317.     struct trans_list *t;
  318.  
  319.     if (t00 != (XtTranslations *)NULL)
  320.         XtOverrideTranslations(w, *t00);
  321.  
  322.     for (t = trans_list; t != NULL; t = t->next)
  323.         XtOverrideTranslations(w, lookup_tt(t->name, CN));
  324.  
  325.     *t0 = w->core.tm.translations;
  326. }
  327.  
  328. /*
  329.  * Add or clear a temporary keymap.
  330.  */
  331. void
  332. screen_set_temp_keymap(XtTranslations trans)
  333. {
  334.     if (trans != (XtTranslations)NULL) {
  335.         XtOverrideTranslations(nss.widget, trans);
  336.         XtOverrideTranslations(container, trans);
  337.     } else {
  338.         XtUninstallTranslations(nss.widget);
  339.         XtOverrideTranslations(nss.widget, screen_t0);
  340.         XtUninstallTranslations(container);
  341.         XtOverrideTranslations(container, container_t0);
  342.     }
  343. }
  344.  
  345. /*
  346.  * Change the baselevel keymap.
  347.  */
  348. void
  349. screen_set_keymap(void)
  350. {
  351.     XtUninstallTranslations(nss.widget);
  352.     set_translations(nss.widget, &screen_t00, &screen_t0);
  353.     XtUninstallTranslations(container);
  354.     set_translations(container, &container_t00, &container_t0);
  355. }
  356.  
  357.  
  358. /*
  359.  * Initialize the screen.
  360.  */
  361. void
  362. screen_init(void)
  363. {
  364.     register int i;
  365.  
  366.     /* Initialize ss. */
  367.     nss.cursor_daddr = 0;
  368.     nss.exposed_yet = False;
  369.  
  370.     /* Initialize "gray" bitmap. */
  371.     if (appres.mono)
  372.         gray = XCreatePixmapFromBitmapData(display,
  373.             root_window, (char *)gray_bits,
  374.             gray_width, gray_height,
  375.             appres.foreground, appres.background, screen_depth);
  376.  
  377.     /* Initialize the resize list. */
  378.     init_rsfonts();
  379.  
  380.     /* Initialize the blank map. */
  381.     (void) memset((char *)blank_map, '\0', sizeof(blank_map));
  382.     BKM_SET(CG_null);
  383.     BKM_SET(CG_nobreakspace);
  384.     BKM_SET(CG_ff);
  385.     BKM_SET(CG_cr);
  386.     BKM_SET(CG_nl);
  387.     BKM_SET(CG_em);
  388.     BKM_SET(CG_space);
  389.     for (i = 0; i <= 0xf; i++) {
  390.         BKM_SET(0xc0 + i);
  391.         BKM_SET(0xe0 + i);
  392.     }
  393.  
  394.     /* Register state change callbacks. */
  395.     register_schange(ST_HALF_CONNECT, screen_connect);
  396.     register_schange(ST_CONNECT, screen_connect);
  397.     register_schange(ST_3270_MODE, screen_connect);
  398.  
  399.     /* Initialize the emulated 3270 controller hardware. */
  400.     ctlr_init(ALL_CHANGE);
  401.  
  402.     /* Initialize the actve icon. */
  403.     aicon_init();
  404.  
  405.     /* Initialize the status line. */
  406.     status_init();
  407.  
  408.     /* Initialize the placement of the pop-up keypad. */
  409.     keypad_placement_init();
  410.  
  411.     /* Now call the "reinitialize" function to set everything else up. */
  412.     screen_reinit(ALL_CHANGE);
  413. }
  414.  
  415. /*
  416.  * Re-initialize the screen.
  417.  */
  418. static void
  419. screen_reinit(unsigned cmask)
  420. {
  421.     Dimension cwidth_curr;
  422. #if defined(X3270_KEYPAD) /*[*/
  423.     Dimension mkw;
  424. #endif /*]*/
  425.  
  426.     /* Allocate colors. */
  427.     if (cmask & COLOR_CHANGE) {
  428.         if (appres.m3279) {
  429.             default_color_scheme();
  430.             (void) xfer_color_scheme(appres.color_scheme, False);
  431.         }
  432.         allocate_pixels();
  433.     }
  434.  
  435.     /* Define graphics contexts. */
  436.     if (cmask & (FONT_CHANGE | COLOR_CHANGE))
  437.         make_gcs(&nss);
  438.  
  439.     /* Reinitialize the controller. */
  440.     ctlr_reinit(cmask);
  441.  
  442.     /* Allocate buffers. */
  443.     if (cmask & MODEL_CHANGE) {
  444.         /* Selection bitmap */
  445.         if (selected)
  446.             XtFree((char *)selected);
  447.         selected = (unsigned char *)XtCalloc(sizeof(unsigned char),
  448.                 (maxROWS * maxCOLS + 7) / 8);
  449.  
  450.         /* X display image */
  451.         if (nss.image)
  452.             XtFree((char *)nss.image);
  453.         nss.image = (union sp *)XtCalloc(sizeof(union sp),
  454.                 maxROWS * maxCOLS);
  455.         if (temp_image)
  456.             XtFree((char *)temp_image);
  457.         temp_image = (union sp *)XtCalloc(sizeof(union sp),
  458.                 maxROWS*maxCOLS);
  459.  
  460.         /* render_text buffers */
  461.         if (rt_buf8 != (unsigned char *)CN)
  462.             XtFree((char *)rt_buf8);
  463.         rt_buf8 = (unsigned char *)XtMalloc(maxCOLS);
  464.         if (rt_buf16 != (XChar2b *)NULL)
  465.             XtFree((char *)rt_buf16);
  466.         rt_buf16 = (XChar2b *)XtMalloc(maxCOLS * sizeof(XChar2b));
  467.     } else
  468.         (void) memset((char *) nss.image, 0,
  469.                       sizeof(union sp) * maxROWS * maxCOLS);
  470.  
  471.     /* Set up a container for the menubar, screen and keypad */
  472.  
  473.     if (cmask & (FONT_CHANGE | MODEL_CHANGE)) {
  474.         nss.screen_width  = SCREEN_WIDTH(ss->char_width);
  475.         nss.screen_height = SCREEN_HEIGHT(ss->char_height);
  476.     }
  477.  
  478.     if (toggled(SCROLL_BAR))
  479.         scrollbar_width = SCROLLBAR_WIDTH;
  480.     else
  481.         scrollbar_width = 0;
  482.     container_width = cwidth_nkp = nss.screen_width+2 + scrollbar_width;
  483. #if defined(X3270_KEYPAD) /*[*/
  484.     mkw = min_keypad_width();
  485.     if (kp_placement == kp_integral && container_width < mkw) {
  486.         keypad_xwidth = mkw - container_width;
  487.         container_width = mkw;
  488.     } else
  489.         keypad_xwidth = 0;
  490. #endif /*]*/
  491.  
  492.     if (container == (Widget)NULL) {
  493.         container = XtVaCreateManagedWidget(
  494.             "container", huskWidgetClass, toplevel,
  495.             XtNborderWidth, 0,
  496.             XtNwidth, container_width,
  497.             XtNheight, 10,
  498.             /* XXX -- a temporary lie to make Xt happy */
  499.             NULL);
  500.         save_00translations(container, &container_t00);
  501.         set_translations(container, (XtTranslations *)NULL,
  502.             &container_t0);
  503.         if (appres.mono)
  504.             XtVaSetValues(container, XtNbackgroundPixmap, gray,
  505.                 NULL);
  506.         else
  507.             XtVaSetValues(container, XtNbackground, keypadbg_pixel,
  508.                 NULL);
  509.     }
  510.  
  511.     /* Initialize the menu bar and integral keypad */
  512.  
  513. #if defined(X3270_KEYPAD) /*[*/
  514.     cwidth_curr = appres.keypad_on ? container_width : cwidth_nkp;
  515. #else /*][*/
  516.     cwidth_curr = container_width;
  517. #endif /*]*/
  518.     menubar_height = menubar_qheight(cwidth_curr);
  519.     menubar_init(container, container_width, cwidth_curr);
  520.  
  521.     container_height = menubar_height + nss.screen_height+2;
  522. #if defined(X3270_KEYPAD) /*[*/
  523.     if (kp_placement == kp_integral) {
  524.         (void) keypad_init(container, container_height,
  525.             container_width, False, False);
  526.         keypad_height = keypad_qheight();
  527.     } else
  528.         keypad_height = 0;
  529.     container_height += keypad_height;
  530. #endif /*]*/
  531.  
  532.     /* Create screen and set container dimensions */
  533.     inflate_screen();
  534.  
  535.     /* Create scrollbar */
  536.     scrollbar_init((cmask & MODEL_CHANGE) != 0);
  537.  
  538.     XtRealizeWidget(toplevel);
  539.     nss.window = XtWindow(nss.widget);
  540.     set_mcursor();
  541.  
  542.     /* Reinitialize the active icon. */
  543.     aicon_reinit(cmask);
  544.  
  545.     /* Reinitialize the status line. */
  546.     status_reinit(cmask);
  547.  
  548.     cursor_changed = True;
  549.  
  550.     line_changed = True;
  551.  
  552.     /* Redraw the screen. */
  553.     action_internal(PA_Expose_action, IA_REDRAW, CN, CN);
  554. }
  555.  
  556.  
  557. static void
  558. set_toplevel_sizes(void)
  559. {
  560.     Dimension tw, th;
  561.  
  562. #if defined(X3270_KEYPAD) /*[*/
  563.     tw = container_width - (appres.keypad_on ? 0 : keypad_xwidth);
  564.     th = container_height - (appres.keypad_on ? 0 : keypad_height);
  565. #else /*][*/
  566.     tw = container_width;
  567.     th = container_height;
  568. #endif /*]*/
  569.     XtVaSetValues(toplevel,
  570.         XtNwidth, tw,
  571.         XtNheight, th,
  572.         NULL);
  573.     if (!appres.allow_resize)
  574.         XtVaSetValues(toplevel,
  575.             XtNbaseWidth, tw,
  576.             XtNbaseHeight, th,
  577.             XtNminWidth, tw,
  578.             XtNminHeight, th,
  579.             XtNmaxWidth, tw,
  580.             XtNmaxHeight, th,
  581.             NULL);
  582.     XtVaSetValues(container,
  583.         XtNwidth, container_width,
  584.         XtNheight, container_height,
  585.         NULL);
  586.     main_width = tw;
  587.     main_height = th;
  588.  
  589.     /*
  590.      * Start a timer ticking, in case the window manager doesn't approve
  591.      * of the change.
  592.      */
  593.     if (configure_ticking)
  594.         XtRemoveTimeOut(configure_id);
  595.     configure_id = XtAppAddTimeOut(appcontext, 500, configure_stable, 0);
  596.     configure_ticking = True;
  597.  
  598.     keypad_move();
  599. }
  600.  
  601. static void
  602. inflate_screen(void)
  603. {
  604.     /* Create the screen window */
  605.     if (nss.widget == NULL) {
  606.         nss.widget = XtVaCreateManagedWidget(
  607.             "screen", widgetClass, container,
  608.             XtNwidth, nss.screen_width,
  609.             XtNheight, nss.screen_height,
  610.             XtNx,
  611. #if defined(X3270_KEYPAD) /*[*/
  612.             appres.keypad_on ? (keypad_xwidth / 2) : 0,
  613. #else /*][*/
  614.             0,
  615. #endif /*]*/
  616.             XtNy, menubar_height,
  617.             XtNbackground,
  618.             appres.mono ? appres.background : colorbg_pixel,
  619.             NULL);
  620.         save_00translations(nss.widget, &screen_t00);
  621.         set_translations(nss.widget, (XtTranslations *)NULL,
  622.             &screen_t0);
  623.     } else {
  624.         XtVaSetValues(nss.widget,
  625.             XtNwidth, nss.screen_width,
  626.             XtNheight, nss.screen_height,
  627.             XtNx,
  628. #if defined(X3270_KEYPAD) /*[*/
  629.             appres.keypad_on ? (keypad_xwidth / 2) : 0,
  630. #else /*][*/
  631.             0,
  632. #endif /*]*/
  633.             XtNy, menubar_height,
  634.             XtNbackground,
  635.             appres.mono ? appres.background : colorbg_pixel,
  636.             NULL);
  637.     }
  638.  
  639.     /* Set the container and toplevel dimensions */
  640.     XtVaSetValues(container,
  641.         XtNwidth, container_width,
  642.         XtNheight, container_height,
  643.         NULL);
  644.  
  645.     set_toplevel_sizes();
  646. }
  647.  
  648. /* Scrollbar support. */
  649. void
  650. screen_set_thumb(float top, float shown)
  651. {
  652.     if (toggled(SCROLL_BAR))
  653.         XawScrollbarSetThumb(scrollbar, top, shown);
  654. }
  655.  
  656. static void
  657. screen_scroll_proc(Widget w unused, XtPointer client_data unused,
  658.     XtPointer position)
  659. {
  660.     scroll_proc((int)position, (int)nss.screen_height);
  661. }
  662.  
  663. static void
  664. screen_jump_proc(Widget w unused, XtPointer client_data unused,
  665.     XtPointer percent_ptr)
  666. {
  667.     jump_proc(*(float *)percent_ptr);
  668. }
  669.  
  670. /* Create, move, or reset the scrollbar. */
  671. static void
  672. scrollbar_init(Boolean is_reset)
  673. {
  674.     if (!scrollbar_width) {
  675.         if (scrollbar != (Widget)NULL)
  676.             XtUnmapWidget(scrollbar);
  677.     } else {
  678.         if (scrollbar == (Widget)NULL) {
  679.             scrollbar = XtVaCreateManagedWidget(
  680.                 "scrollbar", scrollbarWidgetClass,
  681.                 container,
  682.                 XtNx, nss.screen_width+1
  683. #if defined(X3270_KEYPAD) /*[*/
  684.                     + (appres.keypad_on ? (keypad_xwidth / 2) : 0)
  685. #endif /*]*/
  686.                     ,
  687.                 XtNy, menubar_height,
  688.                 XtNwidth, scrollbar_width-1,
  689.                 XtNheight, nss.screen_height,
  690.                 XtNbackground, appres.mono ?
  691.                 appres.background : keypadbg_pixel,
  692.                 NULL);
  693.             XtAddCallback(scrollbar, XtNscrollProc,
  694.                 screen_scroll_proc, NULL);
  695.             XtAddCallback(scrollbar, XtNjumpProc,
  696.                 screen_jump_proc, NULL);
  697.         } else {
  698.             XtVaSetValues(scrollbar,
  699.                 XtNx, nss.screen_width+1
  700. #if defined(X3270_KEYPAD) /*[*/
  701.                     + (appres.keypad_on ? (keypad_xwidth / 2) : 0)
  702. #endif /*]*/
  703.                     ,
  704.                 XtNy, menubar_height,
  705.                 XtNwidth, scrollbar_width-1,
  706.                 XtNheight, nss.screen_height,
  707.                 XtNbackground, appres.mono ?
  708.                 appres.background : keypadbg_pixel,
  709.                 NULL);
  710.             XtMapWidget(scrollbar);
  711.         }
  712.         XawScrollbarSetThumb(scrollbar, 0.0, 1.0);
  713.  
  714.     }
  715.  
  716.     /*
  717.      * If the screen dimensions have changed, reallocate the scroll
  718.      * save area.
  719.      */
  720.     if (is_reset || !scroll_initted)
  721.         scroll_init();
  722.     else
  723.         rethumb();
  724. }
  725.  
  726. /* Turn the scrollbar on or off */
  727. void
  728. toggle_scrollBar(struct toggle *t unused, enum toggle_type tt unused)
  729. {
  730.     scrollbar_changed = True;
  731.  
  732.     if (toggled(SCROLL_BAR)) {
  733.         scrollbar_width = SCROLLBAR_WIDTH;
  734.         screen_redo = REDO_SCROLLBAR;
  735.     } else {
  736.         scroll_to_bottom();
  737.         scrollbar_width = 0;
  738.     }
  739.  
  740.     screen_reinit(SCROLL_CHANGE);
  741.     if (toggled(SCROLL_BAR))
  742.         rethumb();
  743. }
  744.  
  745. /*
  746.  * Called when a host connects, disconnects or changes ANSI/3270 mode.
  747.  */
  748. static void
  749. screen_connect(Boolean ignored unused)
  750. {
  751.     if (!screen_buf)
  752.         return;        /* too soon */
  753.  
  754.     if (CONNECTED) {
  755.         ctlr_erase(True);
  756.         if (IN_3270)
  757.             scroll_round();
  758.         cursor_on();
  759.         schedule_cursor_blink();
  760.     } else {
  761.         if (appres.disconnect_clear)
  762.             ctlr_erase(True);
  763.         (void) cursor_off();
  764.     }
  765.  
  766.     mcursor_normal();
  767. }
  768.  
  769. /*
  770.  * Mouse cursor changes
  771.  */
  772.  
  773. static void
  774. set_mcursor(void)
  775. {
  776.     switch (mcursor_state) {
  777.         case LOCKED:
  778.         XDefineCursor(display, nss.window, appres.locked_mcursor);
  779.         break;
  780.         case NORMAL:
  781.         XDefineCursor(display, nss.window, appres.normal_mcursor);
  782.         break;
  783.         case WAIT:
  784.         XDefineCursor(display, nss.window, appres.wait_mcursor);
  785.         break;
  786.     }
  787.     lock_icon(mcursor_state);
  788. }
  789.  
  790. void
  791. mcursor_normal(void)
  792. {
  793.     if (CONNECTED)
  794.         mcursor_state = NORMAL;
  795.     else if (HALF_CONNECTED)
  796.         mcursor_state = WAIT;
  797.     else
  798.         mcursor_state = LOCKED;
  799.     set_mcursor();
  800. }
  801.  
  802. void
  803. mcursor_waiting(void)
  804. {
  805.     mcursor_state = WAIT;
  806.     set_mcursor();
  807. }
  808.  
  809. void
  810. mcursor_locked(void)
  811. {
  812.     mcursor_state = LOCKED;
  813.     set_mcursor();
  814. }
  815.  
  816. #if defined(X3270_KEYPAD) /*[*/
  817. /*
  818.  * Called from the keypad button to expose or hide the integral keypad.
  819.  */
  820. void
  821. screen_showikeypad(Boolean on)
  822. {
  823.     if (on)
  824.         screen_redo = REDO_KEYPAD;
  825.  
  826.     inflate_screen();
  827.     if (keypad_xwidth > 0) {
  828.         if (scrollbar != (Widget) NULL)
  829.             scrollbar_init(False);
  830.         menubar_resize(on ? container_width : cwidth_nkp);
  831.     }
  832. }
  833. #endif /*]*/
  834.  
  835.  
  836. /*
  837.  * The host just wrote a blinking character; make sure it blinks
  838.  */
  839. void
  840. blink_start(void)
  841. {
  842.     text_blinkers_exist = True;
  843.     if (!text_blink_scheduled) {
  844.         /* Start in "on" state and start first iteration */
  845.         text_blinking_on = True;
  846.         schedule_text_blink();
  847.     }
  848. }
  849.  
  850. /*
  851.  * Restore blanked blinking text
  852.  */
  853. static void
  854. text_blink_it(XtPointer closure unused, XtIntervalId *id unused)
  855. {
  856.     /* Flip the state. */
  857.     text_blinking_on = !text_blinking_on;
  858.  
  859.     /* Force a screen redraw. */
  860.     ctlr_changed(0, ROWS*COLS);
  861.  
  862.     /* If there is still blinking text, schedule the next iteration */
  863.     if (text_blinkers_exist)
  864.         schedule_text_blink();
  865.     else
  866.         text_blink_scheduled = False;
  867. }
  868.  
  869. /*
  870.  * Schedule an event to restore blanked blinking text
  871.  */
  872. static void
  873. schedule_text_blink(void)
  874. {
  875.     text_blink_scheduled = True;
  876.     text_blink_id = XtAppAddTimeOut(appcontext, 500, text_blink_it, 0);
  877. }
  878.  
  879.  
  880. /*
  881.  * Make the (displayed) cursor disappear.  Returns a Boolean indiciating if
  882.  * the cursor was on before the call.
  883.  */
  884. static Boolean
  885. cursor_off(void)
  886. {
  887.     if (cursor_displayed) {
  888.         cursor_displayed = False;
  889.         put_cursor(ss->cursor_daddr, False);
  890.         return True;
  891.     } else
  892.         return False;
  893. }
  894.  
  895.  
  896.  
  897. /*
  898.  * Blink the cursor
  899.  */
  900. static void
  901. cursor_blink_it(XtPointer closure unused, XtIntervalId *id unused)
  902. {
  903.     cursor_blink_pending = False;
  904.     if (!CONNECTED || !toggled(CURSOR_BLINK))
  905.         return;
  906.     if (cursor_displayed) {
  907.         if (in_focus)
  908.             (void) cursor_off();
  909.     } else
  910.         cursor_on();
  911.     schedule_cursor_blink();
  912. }
  913.  
  914. /*
  915.  * Schedule a cursor blink
  916.  */
  917. static void
  918. schedule_cursor_blink(void)
  919. {
  920.     if (!toggled(CURSOR_BLINK) || cursor_blink_pending)
  921.         return;
  922.     cursor_blink_pending = True;
  923.     cursor_blink_id = XtAppAddTimeOut(appcontext, 500, cursor_blink_it, 0);
  924. }
  925.  
  926. /*
  927.  * Cancel a cursor blink
  928.  */
  929. static void
  930. cancel_blink(void)
  931. {
  932.     if (cursor_blink_pending) {
  933.         XtRemoveTimeOut(cursor_blink_id);
  934.         cursor_blink_pending = False;
  935.     }
  936. }
  937.  
  938. /*
  939.  * Toggle cursor blinking (called from menu)
  940.  */
  941. void
  942. toggle_cursorBlink(struct toggle *t unused, enum toggle_type tt unused)
  943. {
  944.     if (!CONNECTED)
  945.         return;
  946.  
  947.     if (toggled(CURSOR_BLINK))
  948.         schedule_cursor_blink();
  949.     else
  950.         cursor_on();
  951. }
  952.  
  953. /*
  954.  * Make the cursor visible at its (possibly new) location.
  955.  */
  956. static void
  957. cursor_on(void)
  958. {
  959.     if (cursor_enabled && !cursor_displayed) {
  960.         cursor_displayed = True;
  961.         put_cursor(cursor_addr, True);
  962.         ss->cursor_daddr = cursor_addr;
  963.         cursor_changed = False;
  964.     }
  965. }
  966.  
  967.  
  968. /*
  969.  * Toggle the cursor (block/underline).
  970.  */
  971. void
  972. toggle_altCursor(struct toggle *t, enum toggle_type tt unused)
  973. {
  974.     Boolean was_on;
  975.  
  976.     /* do_toggle already changed the value; temporarily change it back */
  977.     toggle_toggle(t);
  978.  
  979.     was_on = cursor_off();
  980.  
  981.     /* Now change it back again */
  982.     toggle_toggle(t);
  983.  
  984.     if (was_on)
  985.         cursor_on();
  986. }
  987.  
  988.  
  989. /*
  990.  * Move the cursor to the specified buffer address.
  991.  */
  992. void
  993. cursor_move(int baddr)
  994. {
  995.     cursor_addr = baddr;
  996.     cursor_pos();
  997. }
  998.  
  999. /*
  1000.  * Display the cursor position on the status line
  1001.  */
  1002. static void
  1003. cursor_pos(void)
  1004. {
  1005.     if (!toggled(CURSOR_POS) || !CONNECTED)
  1006.         return;
  1007.     status_cursor_pos(cursor_addr);
  1008. }
  1009.  
  1010. /*
  1011.  * Toggle the display of the cursor position
  1012.  */
  1013. void
  1014. toggle_cursorPos(struct toggle *t unused, enum toggle_type tt unused)
  1015. {
  1016.     if (toggled(CURSOR_POS))
  1017.         cursor_pos();
  1018.     else
  1019.         status_uncursor_pos();
  1020. }
  1021.  
  1022. /*
  1023.  * Enable or disable cursor display (used by scroll logic)
  1024.  */
  1025. void
  1026. enable_cursor(Boolean on)
  1027. {
  1028.     if ((cursor_enabled = on) && CONNECTED) {
  1029.         cursor_on();
  1030.         cursor_changed = True;
  1031.     } else
  1032.         (void) cursor_off();
  1033. }
  1034.  
  1035.  
  1036. /*
  1037.  * Redraw the screen.
  1038.  */
  1039. static void
  1040. do_redraw(Widget w, XEvent *event, String *params unused,
  1041.     Cardinal *num_params unused)
  1042. {
  1043.     int    x, y, width, height;
  1044.     int    startcol, ncols;
  1045.     int    startrow, endrow, row;
  1046.     register int i;
  1047.     int     c0;
  1048.  
  1049.     if (w == nss.widget) {
  1050.         keypad_first_up();
  1051.         if (appres.active_icon && iconic) {
  1052.             ss = &nss;
  1053.             iconic = False;
  1054.         }
  1055.     } else if (appres.active_icon && w == iss.widget) {
  1056.         if (appres.active_icon && !iconic) {
  1057.             ss = &iss;
  1058.             iconic = True;
  1059.         }
  1060.     } else if (event)
  1061.         return;
  1062.  
  1063.     /* Only redraw as necessary for an expose event */
  1064.     if (event && event->type == Expose) {
  1065.         ss->exposed_yet = True;
  1066.         x = event->xexpose.x;
  1067.         y = event->xexpose.y;
  1068.         width = event->xexpose.width;
  1069.         height = event->xexpose.height;
  1070.         startrow = ssY_TO_ROW(y);
  1071.         if (startrow < 0)
  1072.             startrow = 0;
  1073.         if (startrow > 0)
  1074.             startrow--;
  1075.         endrow = ssY_TO_ROW(y+height);
  1076.         endrow = endrow >= maxROWS ? maxROWS : endrow + 1;
  1077.         startcol = ssX_TO_COL(x);
  1078.         if (startcol < 0)
  1079.             startcol = 0;
  1080.         if (startcol > 0)
  1081.             startcol--;
  1082.         ncols = ssX_TO_COL(width+ss->char_width) + 2;
  1083.         while ((ROWCOL_TO_BA(startrow, startcol) % maxCOLS) + ncols > maxCOLS)
  1084.             ncols--;
  1085.         for (row = startrow; row < endrow; row++) {
  1086.             (void) memset((char *) &ss->image[ROWCOL_TO_BA(row, startcol)],
  1087.                   0, ncols * sizeof(union sp));
  1088.             if (ss->debugging_font) {
  1089.                 c0 = ROWCOL_TO_BA(row, startcol);
  1090.  
  1091.                 for (i = 0; i < ncols; i++)
  1092.                     ss->image[c0 + i].bits.cg = CG_space;
  1093.             }
  1094.         }
  1095.                         
  1096.     } else {
  1097.         XFillRectangle(display, ss->window,
  1098.             get_gc(ss, INVERT_COLOR(0)),
  1099.             0, 0, ss->screen_width, ss->screen_height);
  1100.         (void) memset((char *) ss->image, 0,
  1101.                       (maxROWS*maxCOLS) * sizeof(union sp));
  1102.         if (ss->debugging_font)
  1103.             for (i = 0; i < maxROWS*maxCOLS; i++)
  1104.                 ss->image[i].bits.cg = CG_space;
  1105.         ss->copied = False;
  1106.     }
  1107.     ctlr_changed(0, ROWS*COLS);
  1108.     cursor_changed = True;
  1109.     if (!appres.active_icon || !iconic) {
  1110.         line_changed = True;
  1111.         status_touch();
  1112.     }
  1113. }
  1114.  
  1115. /*
  1116.  * Explicitly redraw the screen (invoked from the keyboard).
  1117.  */
  1118. void
  1119. Redraw_action(Widget w, XEvent *event, String *params, Cardinal *num_params)
  1120. {
  1121.     action_debug(Redraw_action, event, params, num_params);
  1122.     do_redraw(w, event, params, num_params);
  1123. }
  1124.  
  1125. /*
  1126.  * Implicitly redraw the screen (triggered by Expose events).
  1127.  */
  1128. void
  1129. PA_Expose_action(Widget w, XEvent *event, String *params, Cardinal *num_params)
  1130. {
  1131. #if defined(INTERNAL_ACTION_DEBUG) /*[*/
  1132.     action_debug(PA_Expose_action, event, params, num_params);
  1133. #endif /*]*/
  1134.     do_redraw(w, event, params, num_params);
  1135. }
  1136.  
  1137.  
  1138. /*
  1139.  * Redraw the changed parts of the screen.
  1140.  */
  1141.  
  1142. void
  1143. screen_disp(void)
  1144. {
  1145.  
  1146.     /* No point in doing anything if we aren't visible yet. */
  1147.     if (!ss->exposed_yet)
  1148.         return;
  1149.  
  1150.     /*
  1151.      * We don't set "cursor_changed" when the host moves the cursor,
  1152.      * 'cause he might just move it back later.  Set it here if the cursor
  1153.      * has moved since the last call to screen_disp.
  1154.      */
  1155.     if (cursor_addr != ss->cursor_daddr)
  1156.         cursor_changed = True;
  1157.  
  1158.     /*
  1159.      * If only the cursor has changed (and not the screen image), draw it.
  1160.      */
  1161.     if (cursor_changed && !screen_changed) {
  1162.         if (cursor_off())
  1163.             cursor_on();
  1164.     }
  1165.  
  1166.     /*
  1167.      * Redraw the parts of the screen that need refreshing, and redraw the
  1168.      * cursor if necessary.
  1169.      */
  1170.     if (screen_changed) {
  1171.         Boolean    was_on = False;
  1172.  
  1173.         /* Draw the new screen image into "temp_image" */
  1174.         if (screen_changed)
  1175.             draw_fields(temp_image, first_changed, last_changed);
  1176.  
  1177.         /* Set "cursor_changed" if the text under it has changed. */
  1178.         if (ss->image[fl_baddr(cursor_addr)].word !=
  1179.             temp_image[fl_baddr(cursor_addr)].word)
  1180.             cursor_changed = True;
  1181.  
  1182.         /* Undraw the cursor, if necessary. */
  1183.         if (cursor_changed)
  1184.             was_on = cursor_off();
  1185.  
  1186.         /* Intelligently update the X display with the new text. */
  1187.         resync_display(temp_image, first_changed, last_changed);
  1188.  
  1189.         /* Redraw the cursor. */
  1190.         if (was_on)
  1191.             cursor_on();
  1192.  
  1193.         screen_changed = False;
  1194.         first_changed = -1;
  1195.         last_changed = -1;
  1196.     }
  1197.  
  1198.     if (!appres.active_icon || !iconic) {
  1199.         /* Refresh the status line. */
  1200.         status_disp();
  1201.  
  1202.         /* Refresh the line across the bottom of the screen. */
  1203.         if (line_changed) {
  1204.             XDrawLine(display, ss->window,
  1205.                 get_gc(ss, GC_NONDEFAULT | DEFAULT_PIXEL),
  1206.                 0,
  1207.                 ssROW_TO_Y(maxROWS-1)+SGAP-1,
  1208.                 ssCOL_TO_X(maxCOLS)+HHALO,
  1209.                 ssROW_TO_Y(maxROWS-1)+SGAP-1);
  1210.             line_changed = False;
  1211.         }
  1212.     }
  1213.     draw_aicon_label();
  1214. }
  1215.  
  1216.  
  1217. /*
  1218.  * Render a blank rectangle on the X display.
  1219.  */
  1220. static void
  1221. render_blanks(int baddr, int height, union sp *buffer)
  1222. {
  1223.     int x, y;
  1224.  
  1225. #if defined(_ST) /*[*/
  1226.     (void) printf("render_blanks(baddr=%s, height=%d)\n", rcba(baddr),
  1227.         height);
  1228. #endif /*]*/
  1229.  
  1230.     x = ssCOL_TO_X(BA_TO_COL(baddr));
  1231.     y = ssROW_TO_Y(BA_TO_ROW(baddr));
  1232.  
  1233.     XFillRectangle(display, ss->window,
  1234.         get_gc(ss, INVERT_COLOR(0)),
  1235.         x, y - ss->ascent,
  1236.         (ss->char_width * COLS) + 1, (ss->char_height * height));
  1237.  
  1238.     (void) memmove(&ss->image[baddr], &buffer[baddr],
  1239.                        COLS * height *sizeof(union sp));
  1240. }
  1241.  
  1242. /*
  1243.  * Check if a region of the screen is effectively empty: all blanks or nulls
  1244.  * with no extended highlighting attributes and not selected.
  1245.  *
  1246.  * Works _only_ with non-debug fonts.
  1247.  */
  1248. static Boolean
  1249. empty_space(register union sp *buffer, int len)
  1250. {
  1251.     register int i;
  1252.  
  1253.     for (i = 0; i < len; i++, buffer++) {
  1254.         if (buffer->bits.gr ||
  1255.             buffer->bits.sel ||
  1256.             (buffer->bits.fg & INVERT_MASK) ||
  1257.             !BKM_ISSET(buffer->bits.cg))
  1258.             return False;
  1259.     }
  1260.     return True;
  1261. }
  1262.  
  1263.  
  1264. /*
  1265.  * Reconcile the differences between a region of 'buffer' (what we want on
  1266.  * the X display) and ss->image[] (what is on the X display now).  The region
  1267.  * must not span lines.
  1268.  */
  1269. static void
  1270. resync_text(int baddr, int len, union sp *buffer)
  1271. {
  1272.     static Boolean ever = False;
  1273.     static unsigned long cmask = 0L;
  1274.     static unsigned long gmask = 0L;
  1275.  
  1276. #if defined(_ST) /*[*/
  1277.     (void) printf("resync_text(baddr=%s, len=%d)\n", rcba(baddr), len);
  1278. #endif /*]*/
  1279.     if (!ever) {
  1280.         union sp b;
  1281.  
  1282.         /* Create masks for the "important" fields in an sp. */
  1283.         b.word = 0L;
  1284.         b.bits.fg = COLOR_MASK | INVERT_MASK;
  1285.         b.bits.sel = 1;
  1286.         b.bits.gr = GR_UNDERLINE | GR_INTENSIFY;
  1287.         cmask = b.word;
  1288.  
  1289.         b.word = 0L;
  1290.         b.bits.fg = INVERT_MASK;
  1291.         b.bits.sel = 1;
  1292.         b.bits.gr = 0xf;
  1293.         gmask = b.word;
  1294.  
  1295.         ever = True;
  1296.     }
  1297.  
  1298.     if (!ss->debugging_font &&
  1299.         len > 1 &&
  1300.         empty_space(&buffer[baddr], len)) {
  1301.         int x, y;
  1302.  
  1303.         x = ssCOL_TO_X(BA_TO_COL(baddr));
  1304.         y = ssROW_TO_Y(BA_TO_ROW(baddr));
  1305.  
  1306.         /* All empty, fill a rectangle */
  1307. #if defined(_ST) /*[*/
  1308.         (void) printf("FillRectangle(baddr=%s, len=%d)\n", rcba(baddr),
  1309.             len);
  1310. #endif /*]*/
  1311.         XFillRectangle(display, ss->window,
  1312.             get_gc(ss, INVERT_COLOR(0)),
  1313.             x, y - ss->ascent,
  1314.             (ss->char_width * len) + 1, ss->char_height);
  1315.     } else {
  1316.         unsigned long attrs, attrs2;
  1317.         Boolean has_gr, has_gr2;
  1318.         Boolean empty, empty2;
  1319.         union sp ra;
  1320.         int i;
  1321.         int i0 = 0;
  1322.  
  1323.         ra = buffer[baddr];
  1324.  
  1325.         /* Note the characteristics of the beginning of the region. */
  1326.         attrs = buffer[baddr].word & cmask;
  1327.         has_gr = (buffer[baddr].word & gmask) != 0;
  1328.         empty = !has_gr && BKM_ISSET(buffer[baddr].bits.cg);
  1329.  
  1330.         for (i = 0; i < len; i++) {
  1331.             /* Note the characteristics of this character. */
  1332.             attrs2 = buffer[baddr+i].word & cmask;
  1333.             has_gr2 = (buffer[baddr+i].word & gmask) != 0;
  1334.             empty2 = !has_gr2 && BKM_ISSET(buffer[baddr+i].bits.cg);
  1335.  
  1336.             /* If this character has exactly the same attributes
  1337.                as the current region, simply add it, noting that
  1338.                the region might now not be empty. */
  1339.             if (attrs2 == attrs) {
  1340.                 if (!empty2)
  1341.                     empty = 0;
  1342.                 continue;
  1343.             }
  1344.  
  1345.             /* If this character is empty, and the current region
  1346.                has no GR attributes, pretend it matches. */
  1347.             if (empty2 && !has_gr)
  1348.                 continue;
  1349.  
  1350.             /* If the current region is empty, this character
  1351.                isn't empty, and this character has no GR
  1352.                attributes, change the current region's attributes
  1353.                to this character's attributes and add it. */
  1354.             if (empty && !empty2 && !has_gr2) {
  1355.                 attrs = attrs2;
  1356.                 has_gr = has_gr2;
  1357.                 empty = empty2;
  1358.                 ra = buffer[baddr+i];
  1359.                 continue;
  1360.             }
  1361.  
  1362.             /* Dump the region and start a new one with this
  1363.                character. */
  1364.             render_text(&buffer[baddr+i0], baddr+i0, i - i0, False,
  1365.                 &ra);
  1366.             attrs = attrs2;
  1367.             has_gr = has_gr2;
  1368.             empty = empty2;
  1369.             i0 = i;
  1370.             ra = buffer[baddr+i];
  1371.         }
  1372.  
  1373.         /* Dump the remainder of the region. */
  1374.         render_text(&buffer[baddr+i0], baddr+i0, len - i0, False, &ra);
  1375.     }
  1376.  
  1377.     /* The X display is now correct; update ss->image[]. */
  1378.     (void) memmove(&ss->image[baddr], &buffer[baddr], len*sizeof(union sp));
  1379. }
  1380.  
  1381. /*
  1382.  * Render text onto the X display.  The region must not span lines.
  1383.  */
  1384. static void
  1385. render_text(union sp *buffer, int baddr, int len, Boolean block_cursor,
  1386.     union sp *attrs)
  1387. {
  1388.     int color;
  1389.     int x, y;
  1390.     GC dgc;
  1391.     int sel = attrs->bits.sel;
  1392.     register int i;
  1393.  
  1394. #if defined(_ST) /*[*/
  1395.     (void) printf("render_text(baddr=%s, len=%d)\n", rcba(baddr), len);
  1396. #endif /*]*/
  1397.  
  1398.     if (ss->standard_font) {        /* Standard X font */
  1399.         register unsigned char *xfmap = ss->xfmap;
  1400.  
  1401.         if (toggled(MONOCASE)) {
  1402.             for (i = 0; i < len; i++) {
  1403.                 switch (buffer[i].bits.cs) {
  1404.                     case 0:
  1405.                     rt_buf8[i] =
  1406.                         asc2uc[xfmap[buffer[i].bits.cg]];
  1407.                     break;
  1408.                     case 1:
  1409.                     rt_buf8[i] = ge2asc[buffer[i].bits.cg];
  1410.                     break;
  1411.                     case 2:
  1412.                     rt_buf8[i] = buffer[i].bits.cg;
  1413.                     break;
  1414.                 }
  1415.             }
  1416.         } else for (i = 0; i < len; i++) {
  1417.             switch (buffer[i].bits.cs) {
  1418.                 case 0:
  1419.                 rt_buf8[i] = xfmap[buffer[i].bits.cg];
  1420.                 break;
  1421.                 case 1:
  1422.                 rt_buf8[i] = ge2asc[buffer[i].bits.cg];
  1423.                 break;
  1424.                 case 2:
  1425.                 rt_buf8[i] = buffer[i].bits.cg;
  1426.                 break;
  1427.             }
  1428.         }
  1429.     } else if (ss->extended_3270font) {    /* 16-bit (new) x3270 font */
  1430.         if (toggled(MONOCASE)) {
  1431.             for (i = 0; i < len; i++) {
  1432.                 rt_buf16[i].byte1 = buffer[i].bits.cs;
  1433.                 switch (buffer[i].bits.cs) {
  1434.                     case 0:
  1435.                     rt_buf16[i].byte2 =
  1436.                         cg2uc[buffer[i].bits.cg];
  1437.                     break;
  1438.                     case 1:
  1439.                     case 2:
  1440.                     rt_buf16[i].byte2 = buffer[i].bits.cg;
  1441.                     break;
  1442.                 }
  1443.             }
  1444.         } else
  1445.             for (i = 0; i < len; i++) {
  1446.                 rt_buf16[i].byte1 = buffer[i].bits.cs;
  1447.                 rt_buf16[i].byte2 = buffer[i].bits.cg;
  1448.             }
  1449.     } else {                /* 8-bit (old) x3270 font */
  1450.         if (toggled(MONOCASE)) {
  1451.             for (i = 0; i < len; i++) {
  1452.                 switch (buffer[i].bits.cs) {
  1453.                     case 0:
  1454.                     rt_buf8[i] =
  1455.                         cg2uc[buffer[i].bits.cg];
  1456.                     break;
  1457.                     case 1:
  1458.                     rt_buf8[i] =
  1459.                         ge2cg8[buffer[i].bits.cg];
  1460.                     break;
  1461.                     case 2:
  1462.                     rt_buf8[i] = CG_boxsolid;
  1463.                     break;
  1464.                 }
  1465.             }
  1466.         } else
  1467.             for (i = 0; i < len; i++) {
  1468.                 switch (buffer[i].bits.cs) {
  1469.                     case 0:
  1470.                     rt_buf8[i] = buffer[i].bits.cg;
  1471.                     break;
  1472.                     case 1:
  1473.                     rt_buf8[i] =
  1474.                         ge2cg8[buffer[i].bits.cg];
  1475.                     break;
  1476.                     case 2:
  1477.                     rt_buf8[i] = CG_boxsolid;
  1478.                     break;
  1479.                 }
  1480.             }
  1481.     }
  1482.  
  1483.     x = ssCOL_TO_X(BA_TO_COL(baddr));
  1484.     y = ssROW_TO_Y(BA_TO_ROW(baddr));
  1485.     color = attrs->bits.fg;
  1486.  
  1487.     /* Draw. */
  1488.     if (sel && !block_cursor) {
  1489.         if (!appres.mono)
  1490.             dgc = get_selgc(ss, color);
  1491.         else
  1492.             dgc = get_gc(ss, INVERT_COLOR(color));
  1493.     } else if (block_cursor && !(appres.mono && sel)) {
  1494.         if (appres.use_cursor_color)
  1495.             dgc = ss->invucgc;
  1496.         else
  1497.             dgc = get_gc(ss, INVERT_COLOR(color));
  1498.     } else
  1499.         dgc = get_gc(ss, color);
  1500.  
  1501.     /* Draw the text */
  1502.     if (ss->extended_3270font)
  1503.         XDrawImageString16(display, ss->window, dgc, x, y, rt_buf16,
  1504.             len);
  1505.     else
  1506.         XDrawImageString(display, ss->window, dgc, x, y,
  1507.             (char *)rt_buf8, len);
  1508.     if (ss->overstrike &&
  1509.         ((attrs->bits.gr & GR_INTENSIFY) ||
  1510.          ((appres.mono || (!appres.m3279 && appres.highlight_bold)) &&
  1511.           ((color & BASE_MASK) == FA_INT_HIGH_SEL)))) {
  1512.         if (ss->extended_3270font)
  1513.             XDrawString16(display, ss->window, dgc, x+1, y,
  1514.                 rt_buf16, len);
  1515.         else
  1516.             XDrawString(display, ss->window, dgc, x+1, y,
  1517.                 (char *)rt_buf8, len);
  1518.     }
  1519.     if (attrs->bits.gr & GR_UNDERLINE)
  1520.         XDrawLine(display,
  1521.             ss->window,
  1522.             dgc,
  1523.             x,
  1524.             y - ss->ascent + ss->char_height - 1,
  1525.             x + ss->char_width * len,
  1526.             y - ss->ascent + ss->char_height - 1);
  1527. }
  1528.  
  1529.  
  1530. #if defined(X3270_ANSI) /*[*/
  1531. Boolean
  1532. screen_obscured(void)
  1533. {
  1534.     return ss->obscured;
  1535. }
  1536.  
  1537. /*
  1538.  * Scroll the screen image one row.
  1539.  *
  1540.  * This is the optimized path from ctlr_scroll(); it assumes that
  1541.  * screen_buf[] and ea_buf[] have already been modified and that the screen
  1542.  * can be brought into sync by hammering ss->image and the bitmap.
  1543.  */
  1544. void
  1545. screen_scroll(void)
  1546. {
  1547.     Boolean was_on;
  1548.  
  1549.     if (!ss->exposed_yet)
  1550.         return;
  1551.  
  1552.     was_on = cursor_off();
  1553.     (void) memmove(&ss->image[0], &ss->image[COLS],
  1554.                        (ROWS - 1) * COLS * sizeof(union sp));
  1555.     (void) memmove(&temp_image[0], &temp_image[COLS],
  1556.                        (ROWS - 1) * COLS * sizeof(union sp));
  1557.     (void) memset((char *)&ss->image[(ROWS - 1) * COLS], 0,
  1558.                   COLS * sizeof(union sp));
  1559.     (void) memset((char *)&temp_image[(ROWS - 1) * COLS], 0,
  1560.                   COLS * sizeof(union sp));
  1561.     XCopyArea(display, ss->window, ss->window, get_gc(ss, 0),
  1562.         ssCOL_TO_X(0),
  1563.         ssROW_TO_Y(1) - ss->ascent,
  1564.         ss->char_width * COLS,
  1565.         ss->char_height * (ROWS - 1),
  1566.         ssCOL_TO_X(0),
  1567.         ssROW_TO_Y(0) - ss->ascent);
  1568.     ss->copied = True;
  1569.     XFillRectangle(display, ss->window, get_gc(ss, INVERT_COLOR(0)),
  1570.         ssCOL_TO_X(0),
  1571.         ssROW_TO_Y(ROWS - 1) - ss->ascent,
  1572.         (ss->char_width * COLS) + 1,
  1573.         ss->char_height);
  1574.     if (was_on)
  1575.         cursor_on();
  1576. }
  1577. #endif /*]*/
  1578.  
  1579.  
  1580. /*
  1581.  * Toggle mono-/dual-case mode.
  1582.  */
  1583. void
  1584. toggle_monocase(struct toggle *t unused, enum toggle_type tt unused)
  1585. {
  1586.     (void) memset((char *) ss->image, 0,
  1587.               (ROWS*COLS) * sizeof(union sp));
  1588.     ctlr_changed(0, ROWS*COLS);
  1589. }
  1590.  
  1591. /*
  1592.  * Toggle screen flip
  1593.  */
  1594. void
  1595. screen_flip(void)
  1596. {
  1597.     flipped = !flipped;
  1598.  
  1599.     action_internal(PA_Expose_action, IA_REDRAW, CN, CN);
  1600. }
  1601.  
  1602. /*
  1603.  * "Draw" screen_buf into a buffer
  1604.  */
  1605. static void
  1606. draw_fields(union sp *buffer, int first, int last)
  1607. {
  1608.     int    baddr = 0;
  1609.     unsigned char    *fap;
  1610.     unsigned char    fa;
  1611.     struct ea       *field_ea;
  1612.     struct ea    *char_ea = ea_buf;
  1613.     unsigned char    *sbp = screen_buf;
  1614.     int    field_color;
  1615.     int    zero;
  1616.     Boolean    any_blink = False;
  1617.  
  1618.     /* If there is any blinking text, override the suggested boundaries. */
  1619.     if (text_blinkers_exist) {
  1620.         first = -1;
  1621.         last = -1;
  1622.     }
  1623.  
  1624.     /* Adjust pointers to start of region. */
  1625.     if (first > 0) {
  1626.         baddr += first;
  1627.         char_ea += first;
  1628.         sbp += first;
  1629.         buffer += first;
  1630.     }
  1631.     fap = get_field_attribute(baddr);
  1632.     fa = *fap;
  1633.     field_ea = fa2ea(fap);
  1634.  
  1635.     /* Adjust end of region. */
  1636.     if (last == -1 || last >= ROWS*COLS)
  1637.         last = 0;
  1638.  
  1639.     zero = FA_IS_ZERO(fa);
  1640.     if (field_ea->fg && (!appres.modified_sel || !FA_IS_MODIFIED(fa)))
  1641.         field_color = field_ea->fg & COLOR_MASK;
  1642.     else
  1643.         field_color = fa_color(fa);
  1644.  
  1645.     do {
  1646.         unsigned char    c = *sbp;
  1647.         union sp    b;
  1648.  
  1649.         b.word = 0;    /* clear out all fields */
  1650.  
  1651.         if (IS_FA(c)) {
  1652.             fa = c;
  1653.             field_ea = char_ea;
  1654.             zero = FA_IS_ZERO(fa);
  1655.             if (field_ea->fg && (!appres.modified_sel || !FA_IS_MODIFIED(fa)))
  1656.                 field_color = field_ea->fg & COLOR_MASK;
  1657.             else
  1658.                 field_color = fa_color(fa);
  1659.             if (ss->debugging_font) {
  1660.                 b.bits.cg = c;
  1661.                 if (appres.m3279 || !zero)
  1662.                     b.bits.fg = field_color;
  1663.             } /* otherwise, CG_null in color 0 */
  1664.         } else {
  1665.             unsigned short gr;
  1666.             int e_color;
  1667.  
  1668.             /* Find the right graphic rendition. */
  1669.             gr = char_ea->gr;
  1670.             if (!gr)
  1671.                 gr = field_ea->gr;
  1672.             if (gr & GR_BLINK)
  1673.                 any_blink = True;
  1674.             if (appres.highlight_bold && FA_IS_HIGH(fa))
  1675.                 gr |= GR_INTENSIFY;
  1676.  
  1677.             /* Find the right color. */
  1678.             if (char_ea->fg)
  1679.                 e_color = char_ea->fg & COLOR_MASK;
  1680.             else if (appres.mono && (gr & GR_INTENSIFY))
  1681.                 e_color = fa_color(FA_INT_HIGH_SEL);
  1682.             else
  1683.                 e_color = field_color;
  1684.             if (gr & GR_REVERSE)
  1685.                 e_color = INVERT_COLOR(e_color);
  1686.             if (!appres.mono)
  1687.                 b.bits.fg = e_color;
  1688.  
  1689.             /* Find the right character and character set. */
  1690.             if (zero) {
  1691.                 if (ss->debugging_font)
  1692.                     b.bits.cg = CG_space;
  1693.             } else if ((c != CG_null && c != CG_space) ||
  1694.                        (gr & (GR_REVERSE | GR_UNDERLINE)) ||
  1695.                    ss->debugging_font) {
  1696.  
  1697.                 b.bits.fg = e_color;
  1698.  
  1699.                 /*
  1700.                  * Replace blanked-out blinking text with
  1701.                  * spaces.
  1702.                  */
  1703.                 if (!text_blinking_on && (gr & GR_BLINK))
  1704.                     b.bits.cg = CG_space;
  1705.                 else {
  1706.                     b.bits.cg = c;
  1707.                     if (char_ea->cs)
  1708.                         b.bits.cs = char_ea->cs;
  1709.                     else
  1710.                         b.bits.cs = field_ea->cs;
  1711.                     if (b.bits.cs & CS_GE)
  1712.                         b.bits.cs = 1;
  1713.                     else
  1714.                         b.bits.cs &= CS_MASK;
  1715.                 }
  1716.  
  1717.             } /* otherwise, CG_null */
  1718.  
  1719.             b.bits.gr = gr & (GR_UNDERLINE | GR_INTENSIFY);
  1720.         }
  1721.         if (SELECTED(baddr))
  1722.             b.bits.sel = 1;
  1723.         if (!flipped)
  1724.             *buffer++ = b;
  1725.         else
  1726.             *(buffer + fl_baddr(baddr)) = b;
  1727.         char_ea++;
  1728.         sbp++;
  1729.         INC_BA(baddr);
  1730.     } while (baddr != last);
  1731.  
  1732.     /* Cancel blink timeouts if none were seen this pass. */
  1733.     if (!any_blink)
  1734.         text_blinkers_exist = False;
  1735. }
  1736.  
  1737.  
  1738. /*
  1739.  * Resync the X display with the contents of 'buffer'
  1740.  */
  1741. static void
  1742. resync_display(union sp *buffer, int first, int last)
  1743. {
  1744.     register int    i, j;
  1745.     int        b = 0;
  1746.     int        i0 = -1;
  1747.     Boolean        ccheck;
  1748.     int        fca = fl_baddr(cursor_addr);
  1749.     int        first_row, last_row;
  1750. #    define SPREAD    10
  1751.  
  1752.     if (first < 0) {
  1753.         first_row = 0;
  1754.         last_row = ROWS;
  1755.     } else {
  1756.         first_row = first / COLS;
  1757.         b = first_row * COLS;
  1758.         last_row = (last + (COLS-1)) / COLS;
  1759.     }
  1760.  
  1761.     for (i = first_row; i < last_row; b += COLS, i++) {
  1762.         int d0 = -1;
  1763.         int s0 = -1;
  1764.  
  1765.         /* Has the line changed? */
  1766.         if (!memcmp((char *) &ss->image[b], (char *) &buffer[b],
  1767.             COLS*sizeof(union sp))) {
  1768.             if (i0 >= 0) {
  1769.                 render_blanks(i0 * COLS, i - i0, buffer);
  1770.                 i0 = -1;
  1771.             }
  1772.             continue;
  1773.         }
  1774.  
  1775.         /* Is the new value empty? */
  1776.         if (!ss->debugging_font &&
  1777.             !(fca >= b && fca < (b+COLS)) &&
  1778.             empty_space(&buffer[b], COLS)) {
  1779.             if (i0 < 0)
  1780.                 i0 = i;
  1781.             continue;
  1782.         }
  1783.  
  1784.         /* Yes, it changed, and it isn't blank.
  1785.            Dump any pending blank lines. */
  1786.         if (i0 >= 0) {
  1787.             render_blanks(i0 * COLS, i - i0, buffer);
  1788.             i0 = -1;
  1789.         }
  1790.  
  1791.         /* New text.  Scan it. */
  1792.         ccheck = cursor_displayed &&
  1793.              fca >= b &&
  1794.              fca < (b+COLS);
  1795.         for (j = 0; j < COLS; j++) {
  1796.             if (ccheck && b+j == fca) {
  1797.                 /* Don't repaint over the cursor. */
  1798.  
  1799.                 /* Dump any pending "different" characters. */
  1800.                 if (d0 >= 0)
  1801.                     resync_text(b+d0, j-d0, buffer);
  1802.  
  1803.                 /* Start over. */
  1804.                 d0 = -1;
  1805.                 s0 = -1;
  1806.                 continue;
  1807.             }
  1808.             if (ss->image[b+j].word == buffer[b+j].word) {
  1809.  
  1810.                 /* Character is the same. */
  1811.  
  1812.                 if (d0 >= 0) {
  1813.                     /* Something is pending... */
  1814.                     if (s0 < 0) {
  1815.                         /* Start of "same" area */
  1816.                         s0 = j;
  1817.                     } else {
  1818.                         /* nth matching character */
  1819.                         if (j - s0 > SPREAD) {
  1820.                             /* too many */
  1821.                             resync_text(b+d0,
  1822.                                 s0-d0, buffer);
  1823.                             d0 = -1;
  1824.                             s0 = -1;
  1825.                         }
  1826.                     }
  1827.                 }
  1828.             } else {
  1829.  
  1830.                 /* Character is different. */
  1831.  
  1832.                 /* Forget intermediate matches. */
  1833.                 s0 = -1;
  1834.  
  1835.                 if (d0 < 0)
  1836.                     /* Mark the start. */
  1837.                     d0 = j;
  1838.             }
  1839.         }
  1840.  
  1841.         /* Dump any pending "different" characters. */
  1842.         if (d0 >= 0)
  1843.             resync_text(b+d0, COLS-d0, buffer);
  1844.     }
  1845.     if (i0 >= 0)
  1846.         render_blanks(i0 * COLS, last_row - i0, buffer);
  1847. }
  1848.  
  1849.  
  1850. /*
  1851.  * Support code for cursor redraw.
  1852.  */
  1853.  
  1854. /*
  1855.  * Calculate a flipped baddr.
  1856.  */
  1857. static int
  1858. fl_baddr(int baddr)
  1859. {
  1860.     if (!flipped)
  1861.         return baddr;
  1862.     return ((baddr / COLS) * COLS) + (COLS - (baddr % COLS) - 1);
  1863. }
  1864.  
  1865. /*
  1866.  * Return the proper foreground color for a character position.
  1867.  */
  1868.  
  1869. static int
  1870. char_color(int baddr)
  1871. {
  1872.     unsigned char *fa;
  1873.     int color;
  1874.  
  1875.     fa = get_field_attribute(baddr);
  1876.  
  1877.     /*
  1878.      * Find the color of the character or the field.
  1879.      */
  1880.     if (ea_buf[baddr].fg)
  1881.         color = ea_buf[baddr].fg & COLOR_MASK;
  1882.     else if (fa2ea(fa)->fg && (!appres.modified_sel || !FA_IS_MODIFIED(*fa)))
  1883.         color = fa2ea(fa)->fg & COLOR_MASK;
  1884.     else
  1885.         color = fa_color(*fa);
  1886.  
  1887.     /*
  1888.      * Now apply reverse video.
  1889.      *
  1890.      * One bit of strangeness:
  1891.      *  If the buffer is a field attribute and we aren't using the
  1892.      *  debug font, it's displayed as a blank; don't invert.
  1893.      */
  1894.     if (!((IS_FA(screen_buf[baddr]) && !ss->debugging_font)) &&
  1895.         ((ea_buf[baddr].gr & GR_REVERSE) || (fa2ea(fa)->gr & GR_REVERSE)))
  1896.         color = INVERT_COLOR(color);
  1897.  
  1898.     /*
  1899.      * In monochrome, apply selection status as well.
  1900.      */
  1901.     if (appres.mono && SELECTED(baddr))
  1902.         color = INVERT_COLOR(color);
  1903.  
  1904.     return color;
  1905. }
  1906.  
  1907.  
  1908. /*
  1909.  * Select a GC for drawing a hollow or underscore cursor.
  1910.  */
  1911. static GC
  1912. cursor_gc(int baddr)
  1913. {
  1914.     /*
  1915.      * If they say use a particular color, use it.
  1916.      */
  1917.     if (appres.use_cursor_color)
  1918.         return ss->ucgc;
  1919.     else
  1920.         return get_gc(ss, char_color(baddr));
  1921. }
  1922.  
  1923. /*
  1924.  * Redraw one character.
  1925.  * If 'invert' is true, invert the foreground and background colors.
  1926.  */
  1927. static void
  1928. redraw_char(int baddr, Boolean invert)
  1929. {
  1930.     union sp buffer;
  1931.     unsigned char *fa;
  1932.     int gr;
  1933.     int blank_it = 0;
  1934.  
  1935.     if (!invert) {
  1936.         int flb = fl_baddr(baddr);
  1937.  
  1938.         /* Simply put back what belongs there. */
  1939.         render_text(&ss->image[flb], flb, 1, False, &ss->image[flb]);
  1940.         return;
  1941.     }
  1942.  
  1943.     /*
  1944.      * Fabricate the right thing.
  1945.      * ss->image isn't going to help, because it may contain shortcuts
  1946.      *  for faster display, so we have to construct a buffer to use.
  1947.      */
  1948.     buffer.word = 0L;
  1949.     buffer.bits.cg = screen_buf[baddr];
  1950.     buffer.bits.cs = ea_buf[baddr].cs;
  1951.     if (buffer.bits.cs & CS_GE)
  1952.         buffer.bits.cs = 1;
  1953.     else
  1954.         buffer.bits.cs &= CS_MASK;
  1955.     fa = get_field_attribute(baddr);
  1956.     gr = ea_buf[baddr].gr;
  1957.     if (!gr)
  1958.         gr = fa2ea(fa)->gr;
  1959.     if (IS_FA(screen_buf[baddr])) {
  1960.         if (!ss->debugging_font)
  1961.             blank_it = 1;
  1962.     } else if (FA_IS_ZERO(*fa)) {
  1963.         blank_it = 1;
  1964.     } else if (text_blinkers_exist && !text_blinking_on) {
  1965.         if (gr & GR_BLINK)
  1966.             blank_it = 1;
  1967.     }
  1968.     if (blank_it) {
  1969.         buffer.bits.cg = CG_space;
  1970.         buffer.bits.cs = 0;
  1971.     }
  1972.     buffer.bits.fg = char_color(baddr);
  1973.     buffer.bits.gr |= (gr & GR_INTENSIFY);
  1974.     render_text(&buffer, fl_baddr(baddr), 1, True, &buffer);
  1975. }
  1976.  
  1977. /*
  1978.  * Draw a hollow cursor.
  1979.  */
  1980. static void
  1981. hollow_cursor(int baddr)
  1982. {
  1983.     XDrawRectangle(display,
  1984.         ss->window,
  1985.         cursor_gc(baddr),
  1986.         ssCOL_TO_X(BA_TO_COL(fl_baddr(baddr))),
  1987.         ssROW_TO_Y(BA_TO_ROW(baddr)) - ss->ascent +
  1988.         (appres.mono ? 1 : 0),
  1989.         ss->char_width - 1,
  1990.         ss->char_height - (appres.mono ? 2 : 1));
  1991. }
  1992.  
  1993. /*
  1994.  * Draw an underscore cursor.
  1995.  */
  1996. static void
  1997. underscore_cursor(int baddr)
  1998. {
  1999.     XDrawRectangle(display,
  2000.         ss->window,
  2001.         cursor_gc(baddr),
  2002.         ssCOL_TO_X(BA_TO_COL(fl_baddr(baddr))),
  2003.         ssROW_TO_Y(BA_TO_ROW(baddr)) - ss->ascent +
  2004.         ss->char_height - 2,
  2005.         ss->char_width - 1,
  2006.         1);
  2007. }
  2008.  
  2009. /*
  2010.  * Invert a square over a character.
  2011.  */
  2012. static void
  2013. small_inv_cursor(int baddr)
  2014. {
  2015.     XFillRectangle(display,
  2016.         ss->window,
  2017.         ss->mcgc,
  2018.         ssCOL_TO_X(BA_TO_COL(fl_baddr(baddr))),
  2019.         ssROW_TO_Y(BA_TO_ROW(baddr)) - ss->ascent + 1,
  2020.         ss->char_width,
  2021.         (ss->char_height > 2) ? (ss->char_height - 2) : 1);
  2022. }
  2023.  
  2024. /*
  2025.  * Draw or remove the cursor.
  2026.  */
  2027. static void
  2028. put_cursor(int baddr, Boolean on)
  2029. {
  2030.     /*
  2031.      * If the cursor is being turned off, simply redraw the text under it.
  2032.      */
  2033.     if (!on) {
  2034.         redraw_char(baddr, False);
  2035.         return;
  2036.     }
  2037.  
  2038.     /*
  2039.      * If underscore cursor, redraw the character and draw the underscore.
  2040.      */
  2041.     if (toggled(ALT_CURSOR)) {
  2042.         redraw_char(baddr, False);
  2043.         underscore_cursor(baddr);
  2044.         return;
  2045.     }
  2046.  
  2047.     /*
  2048.      * On, and not an underscore.
  2049.      *
  2050.      * If out of focus, either draw an empty box in its place (if block
  2051.      * cursor) or redraw the underscore (if underscore).
  2052.      */
  2053.     if (!in_focus) {
  2054.         hollow_cursor(baddr);
  2055.         return;
  2056.     }
  2057.  
  2058.     /*
  2059.      * If monochrome, invert a small square over the characters.
  2060.      */
  2061.     if (appres.mono) {
  2062.         small_inv_cursor(baddr);
  2063.         return;
  2064.     }
  2065.  
  2066.     /*
  2067.      * Color: redraw the character in reverse video.
  2068.      */
  2069.     redraw_char(baddr, True);
  2070. }
  2071.  
  2072.  
  2073. /* Allocate a named color. */
  2074. static Boolean
  2075. alloc_color(char *name, enum fallback_color fb_color, Pixel *pixel)
  2076. {
  2077.     XColor cell, db;
  2078.     Screen *s;
  2079.  
  2080.     s = XtScreen(toplevel);
  2081.  
  2082.     if (XAllocNamedColor(display, XDefaultColormapOfScreen(s), name,
  2083.         &cell, &db) != 0) {
  2084.         *pixel = db.pixel;
  2085.         return True;
  2086.     }
  2087.     switch (fb_color) {
  2088.         case FB_WHITE:
  2089.         *pixel = XWhitePixelOfScreen(s);
  2090.         break;
  2091.         case FB_BLACK:
  2092.         *pixel = XBlackPixelOfScreen(s);
  2093.         break;
  2094.     }
  2095.     return False;
  2096. }
  2097.  
  2098. /* Spell out a fallback color. */
  2099. static const char *
  2100. fb_name(enum fallback_color fb_color)
  2101. {
  2102.     switch (fb_color) {
  2103.         case FB_WHITE:
  2104.         return "white";
  2105.         case FB_BLACK:
  2106.         return "black";
  2107.     }
  2108.     return "chartreuse";    /* to keep Gcc -Wall happy */
  2109. }
  2110.  
  2111. /* Allocate color pixels. */
  2112. static void
  2113. allocate_pixels(void)
  2114. {
  2115.  
  2116.     if (appres.mono)
  2117.         return;
  2118.  
  2119.     /* Allocate constant elements. */
  2120.     if (!alloc_color(appres.colorbg_name, FB_BLACK, &colorbg_pixel))
  2121.         xs_warning("Cannot allocate colormap \"%s\" for screen background, using \"black\"",
  2122.             appres.colorbg_name);
  2123.     if (!alloc_color(appres.selbg_name, FB_BLACK, &selbg_pixel))
  2124.         xs_warning("Cannot allocate colormap \"%s\" for select background, using \"black\"",
  2125.             appres.selbg_name);
  2126.     if (!alloc_color(appres.keypadbg_name, FB_WHITE, &keypadbg_pixel))
  2127.         xs_warning("Cannot allocate colormap \"%s\" for keypad background, using \"white\"",
  2128.             appres.keypadbg_name);
  2129.     if (appres.use_cursor_color) {
  2130.         if (!alloc_color(appres.cursor_color_name, FB_WHITE, &cursor_pixel))
  2131.             xs_warning("Cannot allocate colormap \"%s\" for cursor color, using \"white\"",
  2132.                 appres.cursor_color_name);
  2133.     }
  2134.  
  2135.     /* Allocate pseudocolors. */
  2136.     if (!appres.m3279) {
  2137.         if (!alloc_color(appres.normal_name, FB_WHITE, &normal_pixel))
  2138.             xs_warning("Cannot allocate colormap \"%s\" for text, using \"white\"",
  2139.                 appres.normal_name);
  2140.         if (!alloc_color(appres.select_name, FB_WHITE, &select_pixel))
  2141.             xs_warning("Cannot allocate colormap \"%s\" for selectable text, using \"white\"",
  2142.                 appres.select_name);
  2143.         if (!alloc_color(appres.bold_name, FB_WHITE, &bold_pixel))
  2144.             xs_warning("Cannot allocate colormap \"%s\" for bold text, using \"white\"",
  2145.                 appres.bold_name);
  2146.         return;
  2147.     }
  2148. }
  2149.  
  2150. #if defined(X3270_MENUS) /*[*/
  2151. /* Deallocate pixels. */
  2152. static void
  2153. destroy_pixels(void)
  2154. {
  2155.     int i;
  2156.  
  2157.     /*
  2158.      * It would make sense to deallocate many of the pixels here, but
  2159.      * the only available call (XFreeColors) would deallocate cells
  2160.      * that may be in use by other Xt widgets.  Occh.
  2161.      */
  2162.  
  2163.     for (i = 0; i < 16; i++)
  2164.         cpx_done[i] = False;
  2165. }
  2166. #endif /*]*/
  2167.  
  2168. /*
  2169.  * Create graphics contexts.
  2170.  */
  2171. static void
  2172. make_gcs(struct sstate *s)
  2173. {
  2174.     XGCValues xgcv;
  2175.  
  2176.     if (appres.m3279) {
  2177.         int i;
  2178.  
  2179.         for (i = 0; i < NGCS; i++) {
  2180.             if (s->gc[i] != (GC)None) {
  2181.                 XtReleaseGC(toplevel, s->gc[i]);
  2182.                 s->gc[i] = (GC)None;
  2183.             }
  2184.             if (s->gc[i + NGCS] != (GC)None) {
  2185.                 XtReleaseGC(toplevel, s->gc[i + NGCS]);
  2186.                 s->gc[i + NGCS] = (GC)None;
  2187.             }
  2188.             if (s->selgc[i] != (GC)None) {
  2189.                 XtReleaseGC(toplevel, s->selgc[i]);
  2190.                 s->selgc[i] = (GC)None;
  2191.             }
  2192.         }
  2193.     } else {
  2194.         if (!appres.mono) {
  2195.             make_gc_set(s, FA_INT_NORM_NSEL, normal_pixel,
  2196.                 colorbg_pixel);
  2197.             make_gc_set(s, FA_INT_NORM_SEL,  select_pixel,
  2198.                 colorbg_pixel);
  2199.             make_gc_set(s, FA_INT_HIGH_SEL,  bold_pixel,
  2200.                 colorbg_pixel);
  2201.         } else {
  2202.             make_gc_set(s, FA_INT_NORM_NSEL, appres.foreground,
  2203.                 appres.background);
  2204.             make_gc_set(s, FA_INT_NORM_SEL,  appres.foreground,
  2205.                 appres.background);
  2206.             make_gc_set(s, FA_INT_HIGH_SEL,  appres.foreground,
  2207.                 appres.background);
  2208.         }
  2209.     }
  2210.  
  2211.     /* Create monochrome block cursor GC. */
  2212.     if (appres.mono && s->mcgc == (GC)None) {
  2213.         if (screen_depth > 1)
  2214.             xgcv.function = GXinvert;
  2215.         else
  2216.             xgcv.function = GXxor;
  2217.         xgcv.foreground = 1L;
  2218.         s->mcgc = XtGetGC(toplevel,
  2219.             GCForeground|GCFunction,
  2220.             &xgcv);
  2221.     }
  2222.  
  2223.     /* Create explicit cursor color cursor GCs. */
  2224.     if (appres.use_cursor_color) {
  2225.         if (s->ucgc != (GC)None) {
  2226.             XtReleaseGC(toplevel, s->ucgc);
  2227.             s->ucgc = (GC)None;
  2228.         }
  2229.         xgcv.foreground = cursor_pixel;
  2230.         s->ucgc = XtGetGC(toplevel, GCForeground, &xgcv);
  2231.  
  2232.         if (s->invucgc != (GC)None) {
  2233.             XtReleaseGC(toplevel, s->invucgc);
  2234.             s->invucgc = (GC)None;
  2235.         }
  2236.         xgcv.foreground = colorbg_pixel;
  2237.         xgcv.background = cursor_pixel;
  2238.         xgcv.font = s->fid;
  2239.         s->invucgc = XtGetGC(toplevel,
  2240.             GCForeground|GCBackground|GCFont, &xgcv);
  2241.     }
  2242.  
  2243.     /* Set the flag for overstriking bold. */
  2244.     s->overstrike = (s->char_width > 1);
  2245. }
  2246.  
  2247. /* Set up a default color scheme. */
  2248. static void
  2249. default_color_scheme(void)
  2250. {
  2251.     static int default_attrib_colors[4] = {
  2252.         GC_NONDEFAULT | COLOR_GREEN,/* default */
  2253.         GC_NONDEFAULT | COLOR_RED,    /* intensified */
  2254.         GC_NONDEFAULT | COLOR_BLUE,    /* protected */
  2255.         GC_NONDEFAULT | COLOR_WHITE    /* protected, intensified */
  2256.     };
  2257.     int i;
  2258.  
  2259.     ibm_fb = FB_WHITE;
  2260.     for (i = 0; i < 16; i++) {
  2261.         if (color_name[i] != (char *)NULL)
  2262.             XtFree(color_name[i]);
  2263.         color_name[i] = XtNewString("white");
  2264.     }
  2265.     for (i = 0; i < 4; i++)
  2266.         field_colors[i] = default_attrib_colors[i];
  2267. }
  2268.  
  2269. /* Transfer the colorScheme resource into arrays. */
  2270. static Boolean
  2271. xfer_color_scheme(char *cs, Boolean do_popup)
  2272. {
  2273.     int i;
  2274.     char *scheme_name = CN;
  2275.     char *s0 = CN, *scheme = CN;
  2276.     char *tk;
  2277.  
  2278.     char *tmp_color_name[16];
  2279.     enum fallback_color tmp_ibm_fb = FB_WHITE;
  2280.     char *tmp_colorbg_name = CN;
  2281.     char *tmp_selbg_name = CN;
  2282.     int tmp_field_colors[4];
  2283.  
  2284.     if (cs == CN)
  2285.         goto failure;
  2286.     scheme_name = xs_buffer("%s.%s", ResColorScheme, cs);
  2287.     s0 = get_resource(scheme_name);
  2288.     if (s0 == CN) {
  2289.         if (do_popup)
  2290.             popup_an_error("Can't find resource %s", scheme_name);
  2291.         else
  2292.             xs_warning("Can't find resource %s", scheme_name);
  2293.         goto failure;
  2294.     }
  2295.     scheme = s0 = XtNewString(s0);
  2296.     for (i = 0; (tk = strtok(scheme, " \t\n")) != CN; i++) {
  2297.         scheme = CN;
  2298.         if (i > 22) {
  2299.             xs_warning("Ignoring excess data in %s resource",
  2300.                 scheme_name);
  2301.             break;
  2302.         }
  2303.         switch (i) {
  2304.             case  0: case  1: case  2: case  3:
  2305.             case  4: case  5: case  6: case  7:
  2306.             case  8: case  9: case 10: case 11:
  2307.             case 12: case 13: case 14: case 15:    /* IBM color name */
  2308.             tmp_color_name[i] = tk;
  2309.             break;
  2310.             case 16:    /* default for IBM colors */
  2311.             if (!strcmp(tk, "white"))
  2312.                 tmp_ibm_fb = FB_WHITE;
  2313.             else if (!strcmp(tk, "black"))
  2314.                 tmp_ibm_fb = FB_BLACK;
  2315.             else {
  2316.                 if (do_popup)
  2317.                     popup_an_error("Invalid default color");
  2318.                 else
  2319.                     xs_warning("Invalid default color");
  2320.                 goto failure;
  2321.             }
  2322.             break;
  2323.             case 17:    /* screen background */
  2324.             tmp_colorbg_name = tk;
  2325.             break;
  2326.             case 18:    /* select background */
  2327.             tmp_selbg_name = tk;
  2328.             break;
  2329.             case 19: case 20: case 21: case 22:    /* attribute colors */
  2330.             tmp_field_colors[i-19] = atoi(tk);
  2331.             if (tmp_field_colors[i-19] < 0 ||
  2332.                 tmp_field_colors[i-19] > 0x0f) {
  2333.                 if (do_popup)
  2334.                     popup_an_error("Invalid %s resource, ignoring",
  2335.                         scheme_name);
  2336.                 else
  2337.                     xs_warning("Invalid %s resource, ignoring",
  2338.                         scheme_name);
  2339.                 goto failure;
  2340.             }
  2341.             tmp_field_colors[i-19] |= GC_NONDEFAULT;
  2342.         }
  2343.     }
  2344.     if (i < 23) {
  2345.         if (do_popup)
  2346.             popup_an_error("Insufficient data in %s resource",
  2347.                 scheme_name);
  2348.         else
  2349.             xs_warning("Insufficient data in %s resource",
  2350.                 scheme_name);
  2351.         goto failure;
  2352.     }
  2353.  
  2354.     /* Success: transfer to live variables. */
  2355.     for (i = 0; i < 16; i++) {
  2356.         if (color_name[i] != (char *)NULL)
  2357.             XtFree(color_name[i]);
  2358.         color_name[i] = XtNewString(tmp_color_name[i]);
  2359.     }
  2360.     ibm_fb = tmp_ibm_fb;
  2361.     appres.colorbg_name = XtNewString(tmp_colorbg_name);
  2362.     appres.selbg_name = XtNewString(tmp_selbg_name);
  2363.     for (i = 0; i < 4; i++)
  2364.         field_colors[i] = tmp_field_colors[i];
  2365.  
  2366.     /* Clean up and exit. */
  2367.     if (scheme_name != CN)
  2368.         XtFree(scheme_name);
  2369.     if (s0 != CN)
  2370.         XtFree(s0);
  2371.     return True;
  2372.  
  2373.     failure:
  2374.     if (scheme_name != CN)
  2375.         XtFree(scheme_name);
  2376.     if (s0 != CN)
  2377.         XtFree(s0);
  2378.     return False;
  2379. }
  2380.  
  2381. /* Look up a GC, allocating it if necessary. */
  2382. static GC
  2383. get_gc(struct sstate *s, int color)
  2384. {
  2385.     int pixel_index;
  2386.     XGCValues xgcv;
  2387.     GC r;
  2388.  
  2389.     if (color & GC_NONDEFAULT)
  2390.         color &= ~GC_NONDEFAULT;
  2391.     else
  2392.         color = (color & INVERT_MASK) | DEFAULT_PIXEL;
  2393.  
  2394.     if ((r = s->gc[color]) != (GC)None)
  2395.         return r;
  2396.  
  2397.     /* Allocate the pixel. */
  2398.     pixel_index = PIXEL_INDEX(color);
  2399.     if (!cpx_done[pixel_index]) {
  2400.         if (!alloc_color(color_name[pixel_index], ibm_fb,
  2401.                  &cpx[pixel_index])) {
  2402.             static char nbuf[16];
  2403.  
  2404.             (void) sprintf(nbuf, "%d", pixel_index);
  2405.             xs_warning("Cannot allocate colormap \"%s\" for 3279 color %s (%s), using \"%s\"",
  2406.                 color_name[pixel_index], nbuf,
  2407.                 see_color((unsigned char)(pixel_index + 0xf0)),
  2408.                 fb_name(ibm_fb));
  2409.         }
  2410.         cpx_done[pixel_index] = True;
  2411.     }
  2412.  
  2413.     /* Allocate the GC. */
  2414.     xgcv.font = s->fid;
  2415.     if (!(color & INVERT_MASK)) {
  2416.         xgcv.foreground = cpx[pixel_index];
  2417.         xgcv.background = colorbg_pixel;
  2418.     } else {
  2419.         xgcv.foreground = colorbg_pixel;
  2420.         xgcv.background = cpx[pixel_index];
  2421.     }
  2422.     if (s == &nss && pixel_index == DEFAULT_PIXEL) {
  2423.         xgcv.graphics_exposures = True;
  2424.         r = XtGetGC(toplevel,
  2425.             GCForeground|GCBackground|GCFont|GCGraphicsExposures,
  2426.             &xgcv);
  2427.     } else
  2428.         r = XtGetGC(toplevel,
  2429.             GCForeground|GCBackground|GCFont,
  2430.             &xgcv);
  2431.     return s->gc[color] = r;
  2432. }
  2433.  
  2434. /* Look up a selection GC, allocating it if necessary. */
  2435. static GC
  2436. get_selgc(struct sstate *s, int color)
  2437. {
  2438.     XGCValues xgcv;
  2439.     GC r;
  2440.  
  2441.     if (color & GC_NONDEFAULT)
  2442.         color = PIXEL_INDEX(color);
  2443.     else
  2444.         color = DEFAULT_PIXEL;
  2445.  
  2446.     if ((r = s->selgc[color]) != (GC)None)
  2447.         return r;
  2448.  
  2449.     /* Allocate the pixel. */
  2450.     if (!cpx_done[color]) {
  2451.         if (!alloc_color(color_name[color], FB_WHITE, &cpx[color])) {
  2452.             static char nbuf[16];
  2453.  
  2454.             (void) sprintf(nbuf, "%d", color);
  2455.             xs_warning("Cannot allocate colormap \"%s\" for 3279 color %s (%s), using \"white\"",
  2456.                 color_name[color], nbuf,
  2457.                 see_color((unsigned char)(color + 0xf0)));
  2458.         }
  2459.         cpx_done[color] = True;
  2460.     }
  2461.  
  2462.     /* Allocate the GC. */
  2463.     xgcv.font = s->fid;
  2464.     xgcv.foreground = cpx[color];
  2465.     xgcv.background = selbg_pixel;
  2466.     return s->selgc[color] =
  2467.         XtGetGC(toplevel, GCForeground|GCBackground|GCFont, &xgcv);
  2468. }
  2469.  
  2470. /* External entry points for GC allocation. */
  2471.  
  2472. GC
  2473. screen_gc(int color)
  2474. {
  2475.     return get_gc(ss, color | GC_NONDEFAULT);
  2476. }
  2477.  
  2478. GC
  2479. screen_invgc(int color)
  2480. {
  2481.     return get_gc(ss, INVERT_COLOR(color | GC_NONDEFAULT));
  2482. }
  2483.  
  2484. /*
  2485.  * Preallocate a set of graphics contexts for a given color.
  2486.  *
  2487.  * This logic is used only in pseudo-color mode.  In full color mode,
  2488.  * GCs are allocated dynamically by get_gc().
  2489.  */
  2490. static void
  2491. make_gc_set(struct sstate *s, int i, Pixel fg, Pixel bg)
  2492. {
  2493.     XGCValues xgcv;
  2494.  
  2495.     if (s->gc[i] != (GC)None)
  2496.         XtReleaseGC(toplevel, s->gc[i]);
  2497.     xgcv.foreground = fg;
  2498.     xgcv.background = bg;
  2499.     xgcv.graphics_exposures = True;
  2500.     xgcv.font = s->fid;
  2501.     if (s == &nss && !i)
  2502.         s->gc[i] = XtGetGC(toplevel,
  2503.             GCForeground|GCBackground|GCFont|GCGraphicsExposures,
  2504.             &xgcv);
  2505.     else
  2506.         s->gc[i] = XtGetGC(toplevel,
  2507.             GCForeground|GCBackground|GCFont, &xgcv);
  2508.     if (s->gc[NGCS + i] != (GC)None)
  2509.         XtReleaseGC(toplevel, s->gc[NGCS + i]);
  2510.     xgcv.foreground = bg;
  2511.     xgcv.background = fg;
  2512.     s->gc[NGCS + i] = XtGetGC(toplevel, GCForeground|GCBackground|GCFont,
  2513.         &xgcv);
  2514.     if (!appres.mono) {
  2515.         if (s->selgc[i] != (GC)None)
  2516.             XtReleaseGC(toplevel, s->selgc[i]);
  2517.         xgcv.foreground = fg;
  2518.         xgcv.background = selbg_pixel;
  2519.         s->selgc[i] = XtGetGC(toplevel,
  2520.             GCForeground|GCBackground|GCFont, &xgcv);
  2521.     }
  2522. }
  2523.  
  2524.  
  2525. /*
  2526.  * Convert an attribute to a color index.
  2527.  */
  2528. static int
  2529. fa_color(unsigned char fa)
  2530. {
  2531.     if (appres.m3279) {
  2532.         /*
  2533.          * Color indices are the low-order 4 bits of a 3279 color
  2534.          * identifier (0 through 15)
  2535.          */
  2536.         if (appres.modified_sel && FA_IS_MODIFIED(fa))
  2537.             return GC_NONDEFAULT |
  2538.                 (appres.modified_sel_color & 0xf);
  2539.         else if (appres.visual_select && FA_IS_SEL(fa))
  2540.             return GC_NONDEFAULT |
  2541.                 (appres.visual_select_color & 0xf);
  2542.         else
  2543.             return field_colors[(fa >> 1) & 0x03];
  2544.     } else {
  2545.         /*
  2546.          * Color indices are the intensity bits (0 through 2)
  2547.          */
  2548.         if (FA_IS_ZERO(fa) ||
  2549.             (appres.modified_sel && FA_IS_MODIFIED(fa)))
  2550.             return GC_NONDEFAULT | FA_INT_NORM_SEL;
  2551.         else
  2552.             return GC_NONDEFAULT | (fa & FA_INTENSITY);
  2553.     }
  2554. }
  2555.  
  2556.  
  2557.  
  2558. /*
  2559.  * Event handlers for toplevel FocusIn, FocusOut, KeymapNotify and
  2560.  * PropertyChanged events.
  2561.  */
  2562.  
  2563. static Boolean toplevel_focused = False;
  2564. static Boolean keypad_entered = False;
  2565.  
  2566. void
  2567. PA_Focus_action(Widget w unused, XEvent *event, String *params unused,
  2568.     Cardinal *num_params unused)
  2569. {
  2570.     XFocusChangeEvent *fe = (XFocusChangeEvent *)event;
  2571.  
  2572. #if defined(INTERNAL_ACTION_DEBUG) /*[*/
  2573.     action_debug(PA_Focus_action, event, params, num_params);
  2574. #endif /*]*/
  2575.     switch (fe->type) {
  2576.         case FocusIn:
  2577.         if (fe->detail != NotifyPointer) {
  2578.             toplevel_focused = True;
  2579.             screen_focus(True);
  2580.         }
  2581.         break;
  2582.         case FocusOut:
  2583.         toplevel_focused = False;
  2584.         if (!toplevel_focused && !keypad_entered)
  2585.             screen_focus(False);
  2586.         break;
  2587.     }
  2588. }
  2589.  
  2590. void
  2591. PA_EnterLeave_action(Widget w unused, XEvent *event unused,
  2592.     String *params unused, Cardinal *num_params unused)
  2593. {
  2594.     XCrossingEvent *ce = (XCrossingEvent *)event;
  2595.  
  2596. #if defined(INTERNAL_ACTION_DEBUG) /*[*/
  2597.     action_debug(PA_EnterLeave_action, event, params, num_params);
  2598. #endif /*]*/
  2599.     switch (ce->type) {
  2600.         case EnterNotify:
  2601.         keypad_entered = True;
  2602.         screen_focus(True);
  2603.         break;
  2604.         case LeaveNotify:
  2605.         keypad_entered = False;
  2606.         if (!toplevel_focused && !keypad_entered)
  2607.             screen_focus(False);
  2608.         break;
  2609.     }
  2610. }
  2611.  
  2612. void
  2613. PA_KeymapNotify_action(Widget w unused, XEvent *event, String *params unused,
  2614.     Cardinal *num_params unused)
  2615. {
  2616.     XKeymapEvent *k = (XKeymapEvent *)event;
  2617.  
  2618. #if defined(INTERNAL_ACTION_DEBUG) /*[*/
  2619.     action_debug(PA_KeymapNotify_action, event, params, num_params);
  2620. #endif /*]*/
  2621.     shift_event(state_from_keymap(k->key_vector));
  2622. }
  2623.  
  2624. static void
  2625. query_window_state(void)
  2626. {
  2627.     Atom actual_type;
  2628.     int actual_format;
  2629.     unsigned long nitems;
  2630.     unsigned long leftover;
  2631.     unsigned char *data = NULL;
  2632.  
  2633.     /* If using an active icon, the expose events are more reliable. */
  2634.     if (appres.active_icon)
  2635.         return;
  2636.  
  2637.     if (XGetWindowProperty(display, XtWindow(toplevel), a_state, 0L,
  2638.         (long)BUFSIZ, False, a_state, &actual_type, &actual_format,
  2639.         &nitems, &leftover, &data) != Success)
  2640.         return;
  2641.     if (actual_type == a_state && actual_format == 32) {
  2642.         if (*(unsigned long *)data == IconicState)
  2643.             iconic = True;
  2644.         else {
  2645.             iconic = False;
  2646.             invert_icon(False);
  2647.             keypad_first_up();
  2648.         }
  2649.     }
  2650. }
  2651.  
  2652. void
  2653. PA_StateChanged_action(Widget w unused, XEvent *event, String *params,
  2654.     Cardinal *num_params)
  2655. {
  2656. #if defined(INTERNAL_ACTION_DEBUG) /*[*/
  2657.     action_debug(PA_StateChanged_action, event, params, num_params);
  2658. #endif /*]*/
  2659.     query_window_state();
  2660. }
  2661.  
  2662. /*
  2663.  * Handle Shift events (KeyPress and KeyRelease events, or KeymapNotify events
  2664.  * that occur when the mouse enters the window).
  2665.  */
  2666.  
  2667. void
  2668. shift_event(int event_state)
  2669. {
  2670.     static int old_state;
  2671.     Boolean shifted_now =
  2672.         (event_state & (ShiftKeyDown | MetaKeyDown | AltKeyDown)) != 0;
  2673.  
  2674.     if (event_state != old_state) {
  2675.         old_state = event_state;
  2676.         status_shift_mode(event_state);
  2677.         if (shifted != shifted_now) {
  2678.             shifted = shifted_now;
  2679.             keypad_shift();
  2680.         }
  2681.     }
  2682. }
  2683.  
  2684. /*
  2685.  * Handle the mouse entering and leaving the window.
  2686.  */
  2687. static void
  2688. screen_focus(Boolean in)
  2689. {
  2690.     /*
  2691.      * Cancel any pending cursor blink.  If we just came into focus and
  2692.      * have a blinking cursor, we will start a fresh blink cycle below, so
  2693.      * the filled-in cursor is visible for a full turn.
  2694.      */
  2695.     cancel_blink();
  2696.  
  2697.     /*
  2698.      * If the cursor is disabled, simply change internal state.
  2699.      */
  2700.     if (!CONNECTED) {
  2701.         in_focus = in;
  2702.         return;
  2703.     }
  2704.  
  2705.     /*
  2706.      * Change the appearance of the cursor.  Make it hollow out or fill in
  2707.      * instantly, even if it was blinked off originally.
  2708.      */
  2709.     (void) cursor_off();
  2710.     in_focus = in;
  2711.     cursor_on();
  2712.  
  2713.     /*
  2714.      * If we just came into focus and we're supposed to have a blinking
  2715.      * cursor, schedule a blink.
  2716.      */
  2717.     if (in_focus && toggled(CURSOR_BLINK))
  2718.         schedule_cursor_blink();
  2719. }
  2720.  
  2721. /*
  2722.  * Change fonts.
  2723.  */
  2724. void
  2725. SetFont_action(Widget w unused, XEvent *event, String *params,
  2726.     Cardinal *num_params)
  2727. {
  2728.     action_debug(SetFont_action, event, params, num_params);
  2729.     if (check_usage(SetFont_action, *num_params, 1, 1) < 0)
  2730.         return;
  2731.     screen_newfont(params[0], True);
  2732. }
  2733.  
  2734. void
  2735. screen_newfont(char *fontname, Boolean do_popup)
  2736. {
  2737.     const char *emsg;
  2738.     char *old_font;
  2739.  
  2740.     /* Can't change fonts in APL mode. */
  2741.     if (appres.apl_mode)
  2742.         return;
  2743.  
  2744.     if (efontname && !strcmp(fontname, efontname))
  2745.         return;
  2746.  
  2747.     /* Save the old font before trying the new one. */
  2748.     old_font = XtNewString(efontname);
  2749.  
  2750.     /* Try the new one. */
  2751.     if ((emsg = load_fixed_font(fontname))) {
  2752.         if (do_popup)
  2753.             popup_an_error("Font \"%s\"\n%s", fontname, emsg);
  2754.         XtFree(old_font);
  2755.         return;
  2756.     }
  2757.  
  2758.     /* Store the old name away, in case we have to go back to it. */
  2759.     if (redo_old_font != CN)
  2760.         XtFree(redo_old_font);
  2761.     redo_old_font = old_font;
  2762.     screen_redo = REDO_FONT;
  2763.  
  2764.     screen_reinit(FONT_CHANGE);
  2765.     efont_changed = True;
  2766. }
  2767.  
  2768. /*
  2769.  * Load and query a font.
  2770.  * Returns NULL (okay) or an error message.
  2771.  */
  2772. static const char *
  2773. load_fixed_font(const char *name)
  2774. {
  2775.     XFontStruct *f;
  2776.     Font ff;
  2777.     char **matches;
  2778.     int count;
  2779.  
  2780.     if (*name == '!')    /* backwards compatibility */
  2781.         name++;
  2782.  
  2783.     matches = XListFontsWithInfo(display, name, 1, &count, &f);
  2784.     if (matches == (char **)NULL)
  2785.         return "does not exist";
  2786.     ff = XLoadFont(display, matches[0]);
  2787.     set_font_globals(f, name, ff);
  2788.     XFreeFontInfo(matches, f, count);
  2789.     return CN;
  2790. }
  2791.  
  2792. /*
  2793.  * Set globals based on font name and info
  2794.  */
  2795. static void
  2796. set_font_globals(XFontStruct *f, const char *ef, Font ff)
  2797. {
  2798.     unsigned long svalue, svalue2;
  2799.  
  2800.     if (efontname)
  2801.         XtFree(efontname);
  2802.     efontname = XtNewString(ef);
  2803.     nss.char_width  = fCHAR_WIDTH(f);
  2804.     nss.char_height = fCHAR_HEIGHT(f);
  2805.     nss.fid = ff;
  2806.     nss.ascent = f->ascent;
  2807.     nss.descent = f->descent;
  2808.     if (XGetFontProperty(f, XA_FAMILY_NAME, &svalue))
  2809.         nss.standard_font = (Atom) svalue != a_3270;
  2810.     else if (!strncmp(efontname, "3270", 4))
  2811.         nss.standard_font = False;
  2812.     else
  2813.         nss.standard_font = True;
  2814.     if (nss.standard_font) {
  2815.         nss.extended_3270font = False;
  2816.         nss.latin1_font =
  2817.             f->max_char_or_byte2 > 127 &&
  2818.             XGetFontProperty(f, a_registry, &svalue) &&
  2819.             (svalue == a_iso8859 || svalue == a_ISO8859) &&
  2820.             XGetFontProperty(f, a_encoding, &svalue2) &&
  2821.             svalue2 == a_1;
  2822.         nss.xfmap = nss.latin1_font ? cg2asc : cg2asc7;
  2823.         nss.debugging_font = False;
  2824.     } else {
  2825. #if defined(BROKEN_MACH32)
  2826.         nss.extended_3270font = False;
  2827. #else
  2828.         nss.extended_3270font = f->max_byte1 > 0 ||
  2829.             f->max_char_or_byte2 > 255;
  2830. #endif
  2831.         nss.latin1_font = False;
  2832.         nss.xfmap = (unsigned char *)NULL;
  2833.         nss.debugging_font = !strcmp(efontname, "3270d");
  2834.     }
  2835. }
  2836.  
  2837. /*
  2838.  * Font initialization.
  2839.  */
  2840. void
  2841. font_init(void)
  2842. {
  2843.     char *s, *label, *font;
  2844.     struct font_list *f;
  2845.     const char *ef, *emsg;
  2846.  
  2847.     /* Parse the fontMenuList resource. */
  2848.     if (!appres.font_list)
  2849.         xs_error("No %s resource", ResFontList);
  2850.     s = XtNewString(appres.font_list);
  2851.     while (split_dresource(&s, &label, &font) == 1) {
  2852.         f = (struct font_list *)XtMalloc(sizeof(*f));
  2853.         f->label = label;
  2854.         f->font = font;
  2855.         f->next = (struct font_list *)NULL;
  2856.         if (font_list)
  2857.             font_last->next = f;
  2858.         else
  2859.             font_list = f;
  2860.         font_last = f;
  2861.         font_count++;
  2862.     }
  2863.     if (!font_count)
  2864.         xs_error("Invalid %s resource", ResFontList);
  2865.  
  2866.     /* Now figure out which emulator font to load and load it. */
  2867.     if (appres.apl_mode) {
  2868.         /*
  2869.          * APL mode overrides any explicit font selection, but if there
  2870.          * isn't an APL font defined, APL mode is ignored.
  2871.          */
  2872.         if ((appres.efontname = appres.afontname) == NULL) {
  2873.             xs_warning("No %s resource, ignoring APL mode",
  2874.                 ResAplFont);
  2875.             appres.apl_mode = False;
  2876.         }
  2877.     }
  2878.  
  2879.     /*
  2880.      * If there's no explicit emulator font, take the first one off the
  2881.      * menu list.
  2882.      */
  2883.     if (!appres.efontname)
  2884.         appres.efontname = font_list->font;
  2885.  
  2886.     /*
  2887.      * Try the user's selection, then the first off the menu list, then
  2888.      * "fixed", then give up altogether.
  2889.      */
  2890.     ef = appres.efontname;
  2891.     if ((emsg = load_fixed_font(ef)) != CN) {
  2892.         xs_warning("%s \"%s\" %s", ResEmulatorFont, ef, emsg);
  2893.         if (appres.apl_mode) {
  2894.             XtWarning("Ignoring APL mode");
  2895.             appres.apl_mode = False;
  2896.         }
  2897.         if (strcmp(ef, font_list->font)) {
  2898.             ef = font_list->font;
  2899.             emsg = load_fixed_font(ef);
  2900.             if (emsg != CN)
  2901.                 xs_warning("%s \"%s\" %s", ResEmulatorFont, ef,
  2902.                     emsg);
  2903.         }
  2904.         if (emsg != CN) {
  2905.             ef = "fixed";
  2906.             if ((emsg = load_fixed_font(ef)) != CN)
  2907.                 xs_error("%s \"%s\" %s", ResEmulatorFont, ef,
  2908.                     emsg);
  2909.         }
  2910.         xs_warning("Using font \"%s\"", ef);
  2911.     }
  2912. }
  2913.  
  2914. #if defined(X3270_MENUS) /*[*/
  2915. /*
  2916.  * Change models.
  2917.  */
  2918. void
  2919. screen_change_model(int mn, int ovc, int ovr)
  2920. {
  2921.     if (CONNECTED ||
  2922.         (model_num == mn && ovc == ov_cols && ovr == ov_rows))
  2923.         return;
  2924.  
  2925.     redo_old_model = model_num;
  2926.     redo_old_ov_cols = ov_cols;
  2927.     redo_old_ov_rows = ov_rows;
  2928.     screen_redo = REDO_MODEL;
  2929.  
  2930.     model_changed = True;
  2931.     if (ov_cols != ovc || ov_rows != ovr)
  2932.         oversize_changed = True;
  2933.     set_rows_cols(mn, ovc, ovr);
  2934.     st_changed(ST_REMODEL, True);
  2935.     screen_reinit(MODEL_CHANGE);
  2936. }
  2937.  
  2938. /*
  2939.  * Change emulation modes.
  2940.  */
  2941. void
  2942. screen_extended(Boolean extended unused)
  2943. {
  2944.     set_rows_cols(model_num, ov_cols, ov_rows);
  2945.     model_changed = True;
  2946. }
  2947.  
  2948. void
  2949. screen_m3279(Boolean m3279 unused)
  2950. {
  2951.     destroy_pixels();
  2952.     screen_reinit(COLOR_CHANGE);
  2953.     set_rows_cols(model_num, ov_cols, ov_rows);
  2954.     model_changed = True;
  2955. }
  2956.  
  2957. /*
  2958.  * Change color schemes.  Alas, this is destructive if it fails.
  2959.  */
  2960. void
  2961. screen_newscheme(char *s)
  2962. {
  2963.     Boolean xferred;
  2964.  
  2965.     if (!appres.m3279)
  2966.         return;
  2967.  
  2968.     destroy_pixels();
  2969.     xferred = xfer_color_scheme(s, True);
  2970.     if (xferred)
  2971.         appres.color_scheme = s;
  2972.     screen_reinit(COLOR_CHANGE);
  2973.     scheme_changed = True;
  2974. }
  2975.  
  2976. /*
  2977.  * Change character sets.
  2978.  */
  2979. void
  2980. screen_newcharset(char *csname)
  2981. {
  2982.     if (!charset_init(csname))
  2983.         popup_an_error("Cannot find charset \"%s\"", csname);
  2984.     else {
  2985.         screen_reinit(CHARSET_CHANGE);
  2986.         charset_changed = True;
  2987.         popup_an_info("The new character set will only be reflected\n"
  2988.             "in new data from the host");
  2989.     }
  2990. }
  2991. #endif /*]*/
  2992.  
  2993. /*
  2994.  * Visual or not-so-visual bell
  2995.  */
  2996. void
  2997. ring_bell(void)
  2998. {
  2999.     static XGCValues xgcv;
  3000.     static GC bgc;
  3001.     static int initted;
  3002.     struct timeval tv;
  3003.  
  3004.     /* Ring the real display's bell. */
  3005.     if (!appres.visual_bell)
  3006.         XBell(display, appres.bell_volume);
  3007.  
  3008.     /* If we're iconic, invert the icon and return. */
  3009.     if (!appres.active_icon) {
  3010.         query_window_state();
  3011.         if (iconic) {
  3012.             invert_icon(True);
  3013.             return;
  3014.         }
  3015.     }
  3016.  
  3017.     if (!appres.visual_bell || !ss->exposed_yet)
  3018.         return;
  3019.  
  3020.     /* Do a screen flash. */
  3021.  
  3022.     if (!initted) {
  3023.         xgcv.function = GXinvert;
  3024.         bgc = XtGetGC(toplevel, GCFunction, &xgcv);
  3025.         initted = 1;
  3026.     }
  3027.     screen_disp();
  3028.     XFillRectangle(display, ss->window, bgc,
  3029.         0, 0, ss->screen_width, ss->screen_height);
  3030.     XSync(display, 0);
  3031.     tv.tv_sec = 0;
  3032.     tv.tv_usec = 125000;
  3033.     (void) select(0, NULL, NULL, NULL, &tv);
  3034.     XFillRectangle(display, ss->window, bgc,
  3035.         0, 0, ss->screen_width, ss->screen_height);
  3036.     XSync(display, 0);
  3037. }
  3038.  
  3039. /*
  3040.  * Window deletion
  3041.  */
  3042. void
  3043. PA_WMProtocols_action(Widget w, XEvent *event, String *params,
  3044.     Cardinal *num_params)
  3045. {
  3046.     XClientMessageEvent *cme = (XClientMessageEvent *)event;
  3047.  
  3048. #if defined(INTERNAL_ACTION_DEBUG) /*[*/
  3049.     action_debug(PA_WMProtocols_action, event, params, num_params);
  3050. #endif /*]*/
  3051.     if ((Atom)cme->data.l[0] == a_delete_me) {
  3052.         if (w == toplevel)
  3053.             x3270_exit(0);
  3054.         else
  3055.             XtPopdown(w);
  3056.     } else if ((Atom)cme->data.l[0] == a_save_yourself && w == toplevel) {
  3057.         save_yourself();
  3058.     }
  3059. }
  3060.  
  3061.  
  3062. /* Initialize the icon. */
  3063. void
  3064. icon_init(void)
  3065. {
  3066.     icon = XCreateBitmapFromData(display, root_window,
  3067.         (char *) x3270_bits, x3270_width, x3270_height);
  3068.  
  3069.     if (appres.active_icon) {
  3070.         Dimension iw, ih;
  3071.  
  3072.         aicon_font_init();
  3073.         aicon_size(&iw, &ih);
  3074.         icon_shell =  XtVaAppCreateShell(
  3075.             "x3270icon",
  3076.             "X3270",
  3077.             overrideShellWidgetClass,
  3078.             display,
  3079.             XtNwidth, iw,
  3080.             XtNheight, ih,
  3081.             XtNmappedWhenManaged, False,
  3082.             NULL);
  3083.         XtRealizeWidget(icon_shell);
  3084.         XtVaSetValues(toplevel,
  3085.             XtNiconWindow, XtWindow(icon_shell),
  3086.             NULL);
  3087.         if (appres.active_icon) {
  3088.             XtVaSetValues(icon_shell,
  3089.                 XtNbackground, appres.mono ? appres.background
  3090.                                : colorbg_pixel,
  3091.                 NULL);
  3092.         }
  3093.     } else {
  3094.         unsigned i;
  3095.  
  3096.         for (i = 0; i < sizeof(x3270_bits); i++)
  3097.             x3270_bits[i] = ~x3270_bits[i];
  3098.         inv_icon = XCreateBitmapFromData(display, root_window,
  3099.             (char *) x3270_bits, x3270_width, x3270_height);
  3100.         wait_icon = XCreateBitmapFromData(display, root_window,
  3101.             (char *) wait_bits, wait_width, wait_height);
  3102.         for (i = 0; i < sizeof(wait_bits); i++)
  3103.             wait_bits[i] = ~wait_bits[i];
  3104.         inv_wait_icon = XCreateBitmapFromData(display, root_window,
  3105.             (char *) wait_bits, wait_width, wait_height);
  3106.         XtVaSetValues(toplevel,
  3107.             XtNiconPixmap, icon,
  3108.             XtNiconMask, icon,
  3109.             NULL);
  3110.     }
  3111. }
  3112.  
  3113. /*
  3114.  * Initialize the active icon font information.
  3115.  */
  3116. static void
  3117. aicon_font_init(void)
  3118. {
  3119.     XFontStruct *f;
  3120.     Font ff;
  3121.     char **matches;
  3122.     int count;
  3123.  
  3124.     if (!appres.active_icon) {
  3125.         appres.label_icon = False;
  3126.         return;
  3127.     }
  3128.  
  3129.     matches = XListFontsWithInfo(display, appres.icon_font, 1, &count, &f);
  3130.     if (matches == (char **)NULL) {
  3131.         xs_warning("No font %s \"%s\"; activeIcon will not work",
  3132.             ResIconFont, appres.icon_font);
  3133.         appres.active_icon = False;
  3134.         return;
  3135.     }
  3136.     ff = XLoadFont(display, matches[0]);
  3137.     iss.char_width = fCHAR_WIDTH(f);
  3138.     iss.char_height = fCHAR_HEIGHT(f);
  3139.     iss.fid = ff;
  3140.     iss.ascent = f->ascent;
  3141.     XFreeFontInfo(matches, f, count);
  3142.     iss.overstrike = False;
  3143.     iss.standard_font = True;
  3144.     iss.extended_3270font = False;
  3145.     iss.latin1_font = False;
  3146.     iss.debugging_font = False;
  3147.     iss.obscured = True;
  3148.     iss.xfmap = cg2asc7;
  3149.     if (appres.label_icon) {
  3150.         matches = XListFontsWithInfo(display, appres.icon_label_font,
  3151.             1, &count, &ailabel_font);
  3152.         if (matches == (char **)NULL) {
  3153.             xs_warning("Cannot load %s \"%s\" font; labelIcon will not work",
  3154.                 ResIconLabelFont, appres.icon_label_font);
  3155.             appres.label_icon = False;
  3156.             return;
  3157.         }
  3158.         ailabel_font->fid = XLoadFont(display, matches[0]);
  3159.         aicon_label_height = fCHAR_HEIGHT(ailabel_font) + 2;
  3160.     }
  3161. }
  3162.  
  3163. /*
  3164.  * Determine the current size of the active icon.
  3165.  */
  3166. static void
  3167. aicon_size(Dimension *iw, Dimension *ih)
  3168. {
  3169.     XIconSize *is;
  3170.     int count;
  3171.  
  3172.     *iw = maxCOLS*iss.char_width + 2*VHALO;
  3173.     *ih = maxROWS*iss.char_height + 2*HHALO + aicon_label_height;
  3174.     if (XGetIconSizes(display, root_window, &is, &count)) {
  3175.         if (*iw > (unsigned) is[0].max_width)
  3176.             *iw = is[0].max_width;
  3177.         if (*ih > (unsigned) is[0].max_height)
  3178.             *ih = is[0].max_height;
  3179.     }
  3180. }
  3181.  
  3182. /*
  3183.  * Initialize the active icon.  Assumes that aicon_font_init has already been
  3184.  * called.
  3185.  */
  3186. static void
  3187. aicon_init(void)
  3188. {
  3189.     if (!appres.active_icon)
  3190.         return;
  3191.  
  3192.     iss.widget = icon_shell;
  3193.     iss.window = XtWindow(iss.widget);
  3194.     iss.cursor_daddr = 0;
  3195.     iss.exposed_yet = False;
  3196.     if (appres.label_icon) {
  3197.         XGCValues xgcv;
  3198.  
  3199.         xgcv.font = ailabel_font->fid;
  3200.         xgcv.foreground = appres.foreground;
  3201.         xgcv.background = appres.background;
  3202.         ailabel_gc = XtGetGC(toplevel,
  3203.             GCFont|GCForeground|GCBackground,
  3204.             &xgcv);
  3205.     }
  3206. }
  3207.  
  3208. /*
  3209.  * Reinitialize the active icon.
  3210.  */
  3211. static void
  3212. aicon_reinit(unsigned cmask)
  3213. {
  3214.     if (!appres.active_icon)
  3215.         return;
  3216.  
  3217.     if (cmask & (FONT_CHANGE | COLOR_CHANGE))
  3218.         make_gcs(&iss);
  3219.  
  3220.     if (cmask & MODEL_CHANGE) {
  3221.         aicon_size(&iss.screen_width, &iss.screen_height);
  3222.         if (iss.image)
  3223.             XtFree((char *) iss.image);
  3224.         iss.image = (union sp *)
  3225.             XtMalloc(sizeof(union sp) * maxROWS * maxCOLS);
  3226.         XtVaSetValues(iss.widget,
  3227.             XtNwidth, iss.screen_width,
  3228.             XtNheight, iss.screen_height,
  3229.             NULL);
  3230.     }
  3231.     if (cmask & (MODEL_CHANGE | FONT_CHANGE | COLOR_CHANGE))
  3232.         (void) memset((char *)iss.image, 0,
  3233.                   sizeof(union sp) * maxROWS * maxCOLS);
  3234. }
  3235.  
  3236. /* Draw the aicon label */
  3237. static void
  3238. draw_aicon_label(void)
  3239. {
  3240.     int len;
  3241.     Position x;
  3242.  
  3243.     if (!appres.label_icon || !iconic)
  3244.         return;
  3245.  
  3246.     XFillRectangle(display, iss.window,
  3247.         get_gc(&iss, INVERT_COLOR(0)),
  3248.         0, iss.screen_height - aicon_label_height,
  3249.         iss.screen_width, aicon_label_height);
  3250.     len = strlen(aicon_text);
  3251.     x = ((int)iss.screen_width - XTextWidth(ailabel_font, aicon_text, len))
  3252.          / 2;
  3253.     if (x < 0)
  3254.         x = 2;
  3255.     XDrawImageString(display, iss.window, ailabel_gc,
  3256.         x,
  3257.         iss.screen_height - aicon_label_height + ailabel_font->ascent,
  3258.         aicon_text, len);
  3259. }
  3260.  
  3261. /* Set the aicon label */
  3262. void
  3263. set_aicon_label(char *l)
  3264. {
  3265.     if (aicon_text)
  3266.         XtFree(aicon_text);
  3267.     aicon_text = XtNewString(l);
  3268.     draw_aicon_label();
  3269. }
  3270.  
  3271. /* Change the bitmap icon. */
  3272. static void
  3273. flip_icon(Boolean inverted, enum mcursor_state mstate)
  3274. {
  3275.     Pixmap p = icon;
  3276.     
  3277.     if (mstate == LOCKED)
  3278.         mstate = NORMAL;
  3279.     if (appres.active_icon
  3280.         || (inverted == icon_inverted && mstate == icon_cstate))
  3281.         return;
  3282.     switch (mstate) {
  3283.         case WAIT:
  3284.         if (inverted)
  3285.             p = inv_wait_icon;
  3286.         else
  3287.             p = wait_icon;
  3288.         break;
  3289.         case LOCKED:
  3290.         case NORMAL:
  3291.         if (inverted)
  3292.             p = inv_icon;
  3293.         else
  3294.             p = icon;
  3295.         break;
  3296.     }
  3297.     XtVaSetValues(toplevel,
  3298.         XtNiconPixmap, p,
  3299.         XtNiconMask, p,
  3300.         NULL);
  3301.     icon_inverted = inverted;
  3302.     icon_cstate = mstate;
  3303. }
  3304.  
  3305. /*
  3306.  * Invert the icon.
  3307.  */
  3308. static void
  3309. invert_icon(Boolean inverted)
  3310. {
  3311.     flip_icon(inverted, icon_cstate);
  3312. }
  3313.  
  3314. /*
  3315.  * Change to the lock icon.
  3316.  */
  3317. static void
  3318. lock_icon(enum mcursor_state state)
  3319. {
  3320.     flip_icon(icon_inverted, state);
  3321. }
  3322.  
  3323.  
  3324. /*
  3325.  * Resize font list parser.
  3326.  */
  3327. static void
  3328. init_rsfonts(void)
  3329. {
  3330.     char *s;
  3331.     char *name;
  3332.     struct rsfont *r;
  3333.  
  3334.     /* Can't resize in APL mode. */
  3335.     if (appres.apl_mode)
  3336.         return;
  3337.  
  3338.     if ((s = get_resource(ResResizeFontList)) == CN)
  3339.         return;
  3340.  
  3341.     s = XtNewString(s);
  3342.     while (split_lresource(&s, &name) == 1) {
  3343.         XFontStruct *f;
  3344.         char **matches;
  3345.         int count;
  3346.  
  3347.         matches = XListFontsWithInfo(display, name, 1, &count, &f);
  3348.         if (matches == (char **)NULL)
  3349.             continue;
  3350.         r = (struct rsfont *)XtMalloc(sizeof(*r));
  3351.         r->name = name;
  3352.         r->width = fCHAR_WIDTH(f);
  3353.         r->height = fCHAR_HEIGHT(f);
  3354.         XFreeFontInfo(matches, f, count);
  3355.         r->next = rsfonts;
  3356.         rsfonts = r;
  3357.     }
  3358. }
  3359.  
  3360. /*
  3361.  * Handle ConfigureNotify events.
  3362.  */
  3363. static struct {
  3364.     Boolean ticking;
  3365.     Dimension width, height;
  3366.     Position x, y;
  3367.     XtIntervalId id;
  3368. } cn = {
  3369.     False, 0, 0, 0, 0, 0
  3370. };
  3371. static Position main_x = 0, main_y = 0;
  3372.  
  3373. /*
  3374.  * Timeout routine called 0.5 sec after x3270 sets new screen dimensions.
  3375.  * We assume that if this happens, the window manager is happy with our new
  3376.  * size.
  3377.  */
  3378. int host_getnetsock(void);
  3379. int telnet_getreadstat(void);
  3380. static void
  3381. configure_stable(XtPointer closure unused, XtIntervalId *id unused)
  3382. {
  3383. int net_sock=host_getnetsock();
  3384. if((-1!=net_sock)
  3385.  &&(0==telnet_getreadstat()))
  3386.  net_input();
  3387.  
  3388.  
  3389.     trace_event("Reconfigure timer expired\n");
  3390.     configure_ticking = False;
  3391.     if (!cn.ticking)
  3392.         screen_redo = REDO_NONE;
  3393.  
  3394. #ifdef AMIGA
  3395.     configure_id = XtAppAddTimeOut(appcontext, 100, configure_stable, 0);
  3396.     configure_ticking = True;
  3397. #endif
  3398.  
  3399. }
  3400.  
  3401. /* Perform a resize operation. */
  3402. static void
  3403. do_resize(void)
  3404. {
  3405.     struct rsfont *r;
  3406.     struct rsfont *best = (struct rsfont *) NULL;
  3407.  
  3408.     /* What we're doing now is irreversible. */
  3409.     screen_redo = REDO_RESIZE;
  3410.  
  3411.     if (rsfonts == (struct rsfont *)NULL || !appres.allow_resize) {
  3412.         /* Illegal or impossible. */
  3413.         if (rsfonts == (struct rsfont *)NULL)
  3414.             trace_event("  no fonts available for resize\n"
  3415.                 "    reasserting previous size\n");
  3416.         else
  3417.             trace_event("  resize prohibited by resource\n"
  3418.                 "    reasserting previous size\n");
  3419.         set_toplevel_sizes();
  3420.         return;
  3421.     }
  3422.  
  3423.     /*
  3424.      * Recompute the resulting screen area for each font, based on the
  3425.      * current keypad, model, and scrollbar settings.
  3426.      */
  3427.     for (r = rsfonts; r != (struct rsfont *) NULL; r = r->next) {
  3428.         Dimension cw, ch;    /* container_width, container_height */
  3429.  
  3430.         cw = SCREEN_WIDTH(r->width)+2 + scrollbar_width;
  3431. #if defined(X3270_KEYPAD) /*[*/
  3432.         {
  3433.             Dimension mkw;
  3434.  
  3435.             mkw = min_keypad_width();
  3436.             if (kp_placement == kp_integral
  3437.                 && appres.keypad_on
  3438.                 && cw < mkw)
  3439.                 cw = mkw;
  3440.         }
  3441.  
  3442. #endif /*]*/
  3443.         ch = SCREEN_HEIGHT(r->height)+2 + menubar_qheight(cw);
  3444. #if defined(X3270_KEYPAD) /*[*/
  3445.         if (kp_placement == kp_integral && appres.keypad_on)
  3446.             ch += keypad_qheight();
  3447. #endif /*]*/
  3448.         r->total_width = cw;
  3449.         r->total_height = ch;
  3450.         r->area = cw * ch;
  3451.     }
  3452.  
  3453.     /*
  3454.      * Find the the best match for requested dimensions.
  3455.      *
  3456.      * In past, the "best" was the closest area that was larger or
  3457.      * smaller than the current area, whichever was requested.
  3458.      *
  3459.      * Now, if they try to shrink the screen, "they" might be the
  3460.      * window manager enforcing a size restriction, so the "best"
  3461.      * match is the largest window that fits within the requested
  3462.      * dimensions.
  3463.      *
  3464.      * If they try to grow the screen, then the "best" is the
  3465.      * smallest font that lies between the current and requested
  3466.      * length in the requested dimension(s).
  3467.      *
  3468.      * An ambiguous request (one dimension larger and the other smaller)
  3469.      * is taken to be a "larger" request.
  3470.      */
  3471.  
  3472.     if ((cn.width <= main_width && cn.height <= main_height) ||
  3473.         (cn.width > main_width && cn.height > main_height)) {
  3474.         /*
  3475.          * Shrink or two-dimensional grow: Find the largest font which
  3476.          * fits within the new boundaries.
  3477.          *
  3478.          * Note that a shrink in one dimension, with the other
  3479.          * dimension matching, is considered a two-dimensional
  3480.          * shrink.
  3481.          */
  3482.         for (r = rsfonts; r != (struct rsfont *) NULL; r = r->next) {
  3483.             if (r->total_width <= cn.width &&
  3484.                 r->total_height <= cn.height) {
  3485.                 if (best == NULL || r->area > best->area)
  3486.                     best = r;
  3487.             }
  3488.         }
  3489.         /*
  3490.          * If no font is small enough, see if there is a font smaller
  3491.          * than the current font along the requested dimension(s),
  3492.          * which is better than doing nothing.
  3493.          */
  3494.         if (best == NULL) {
  3495.             for (r = rsfonts;
  3496.                  r != (struct rsfont *) NULL;
  3497.                  r = r->next) {
  3498.                 if (cn.width < main_width &&
  3499.                     r->total_width > main_width)
  3500.                     continue;
  3501.                 if (cn.height < main_height &&
  3502.                     r->total_height > main_height)
  3503.                     continue;
  3504.                 if (best == NULL ||
  3505.                     r->area < best->area) {
  3506.                     best = r;
  3507.                 }
  3508.             }
  3509.         }
  3510.     } else {
  3511.         /*
  3512.          * One-dimensional grow: Find the largest font which fits
  3513.          * within the lengthened boundary, and don't constrain the
  3514.          * other dimension.
  3515.          *
  3516.          * Note than an ambiguous change (grow in one dimensional and
  3517.          * shrink in the other) is considered a one-dimensional grow.
  3518.          *
  3519.          * In either case, the "other" dimension is considered
  3520.          * unconstrained.
  3521.          */
  3522.         if (cn.width > main_width) {
  3523.             /* Wider. */
  3524.             for (r = rsfonts;
  3525.                  r != (struct rsfont *) NULL;
  3526.                  r = r->next) {
  3527.                 if (r->total_width <= cn.width &&
  3528.                     (best == NULL ||
  3529.                      r->total_width > best->total_width)) {
  3530.                     best = r;
  3531.                 }
  3532.             }
  3533.         } else {
  3534.             /* Taller. */
  3535.             for (r = rsfonts;
  3536.                  r != (struct rsfont *) NULL;
  3537.                  r = r->next) {
  3538.                 if (r->total_height <= cn.height &&
  3539.                     (best == NULL ||
  3540.                      r->total_height > best->total_height)) {
  3541.                     best = r;
  3542.                 }
  3543.             }
  3544.         }
  3545.     }
  3546.  
  3547.     /* Change fonts. */
  3548.     if (!best || (efontname && !strcmp(best->name, efontname))) {
  3549.         if (cn.width > main_width || cn.height > main_height)
  3550.             trace_event("  no larger font available\n"
  3551.                 "    reasserting previous size\n");
  3552.         else
  3553.             trace_event("  no smaller font available\n"
  3554.                 "    reasserting previous size\n");
  3555.         set_toplevel_sizes();
  3556.     } else {
  3557.         trace_event("    switching to font '%s', new size %dx%d\n",
  3558.             best->name, best->total_width, best->total_height);
  3559.         screen_newfont(best->name, False);
  3560.  
  3561.         /* screen_newfont() sets screen_redo to REDO_FONT. */
  3562.         screen_redo = REDO_RESIZE;
  3563.     }
  3564. }
  3565.  
  3566. /*
  3567.  * Timeout routine called 0.5 sec after x3270 receives the last ConfigureNotify
  3568.  * message.  This is for window managers that use 'continuous' move or resize
  3569.  * actions.
  3570.  */
  3571.  
  3572. static void
  3573. stream_end(XtPointer closure unused, XtIntervalId *id unused)
  3574. {
  3575.     Boolean needs_moving = False;
  3576.     const char *revert = CN;
  3577.     char want_size[64];
  3578.  
  3579.     trace_event("Stream timer expired %hux%hu+%hd+%hd\n",
  3580.         cn.width, cn.height, cn.x, cn.y);
  3581.  
  3582.     /* Not ticking any more. */
  3583.     cn.ticking = False;
  3584.  
  3585.     /* Save the new coordinates in globals for next time. */
  3586.     if (cn.x != main_x || cn.y != main_y) {
  3587.         main_x = cn.x;
  3588.         main_y = cn.y;
  3589.         needs_moving = True;
  3590.     }
  3591.  
  3592.     /*
  3593.      * If the dimensions are correct, do nothing, forget about any
  3594.      * reconfig we may need to revert, and get out.
  3595.      */
  3596.     if (cn.width == main_width && cn.height == main_height) {
  3597.         trace_event("  width and height match\n    doing nothing\n");
  3598.         screen_redo = REDO_NONE;
  3599.         goto done;
  3600.     }
  3601.  
  3602.     /* They're not correct. */
  3603.     (void) sprintf(want_size, "%ux%u", main_width, main_height);
  3604.     trace_event("  size mismatch, want %s\n", want_size);
  3605.  
  3606.     /* If there's a reconfiguration pending, try to undo it. */
  3607.     switch (screen_redo) {
  3608.         case REDO_FONT:
  3609.         revert = "font";
  3610.         screen_newfont(redo_old_font, False);
  3611.         break;
  3612. #if defined(X3270_MENUS) /*[*/
  3613.         case REDO_MODEL:
  3614.         revert = "model number";
  3615.         screen_change_model(redo_old_model,
  3616.             redo_old_ov_cols, redo_old_ov_rows);
  3617.         break;
  3618. #endif /*]*/
  3619. #if defined(X3270_KEYPAD) /*[*/
  3620.         case REDO_KEYPAD:
  3621.         revert = "keypad configuration";
  3622.         screen_showikeypad(appres.keypad_on = False);
  3623.         break;
  3624. #endif /*]*/
  3625.         case REDO_SCROLLBAR:
  3626.         revert = "scrollbar configuration";
  3627.         if (toggled(SCROLL_BAR)) {
  3628.             toggle_toggle(&appres.toggle[SCROLL_BAR]);
  3629.             toggle_scrollBar(&appres.toggle[SCROLL_BAR],
  3630.                 TT_TOGGLE);
  3631.         }
  3632.         break;
  3633.         case REDO_RESIZE:
  3634.         /* Changed fonts in response to a previous user resize. */
  3635.         trace_event("  size reassertion failed, window truncated\n"
  3636.             "    doing nothing\n");
  3637.         screen_redo = REDO_NONE;
  3638.         goto done;
  3639.         case REDO_NONE:
  3640.             /* Initial configuration, or user-generated resize. */
  3641.         do_resize();
  3642.         goto done;
  3643.         default:
  3644.         break;
  3645.     }
  3646.  
  3647.     /* Tell the user what we're doing. */
  3648.     if (revert != CN) {
  3649.         trace_event("    reverting to previous %s\n", revert);
  3650.         popup_an_error("Main window does not fit on the "
  3651.             "X display\n"
  3652.             "Reverting to previous %s", revert);
  3653.     }
  3654.  
  3655.     screen_redo = REDO_NONE;
  3656.  
  3657.     done:
  3658.     if (needs_moving && !iconic)
  3659.         keypad_move();
  3660. }
  3661.  
  3662. void
  3663. PA_ConfigureNotify_action(Widget w unused, XEvent *event, String *params unused,
  3664.     Cardinal *num_params unused)
  3665. {
  3666.     XConfigureEvent *re = (XConfigureEvent *) event;
  3667.     Position xx, yy;
  3668.  
  3669. #if defined(INTERNAL_ACTION_DEBUG) /*[*/
  3670.     action_debug(PA_ConfigureNotify_action, event, params, num_params);
  3671. #endif /*]*/
  3672.  
  3673.     /*
  3674.      * Get the new window coordinates.  If the configure event reports it
  3675.      * as (0,0), ask for it explicitly.
  3676.      */
  3677.     if (re->x || re->y) {
  3678.         xx = re->x;
  3679.         yy = re->y;
  3680.     } else {
  3681.         XtVaGetValues(toplevel, XtNx, &xx, XtNy, &yy, NULL);
  3682.     }
  3683.     trace_event("ConfigureNotify %hux%hu+%hd+%hd\n",
  3684.         re->width, re->height, xx, yy);
  3685.     
  3686.     /* Save the latest values. */
  3687.     cn.x = xx;
  3688.     cn.y = yy;
  3689.     cn.width = re->width;
  3690.     cn.height = re->height;
  3691.  
  3692.     /* Set the stream timer for 0.5 sec from now. */
  3693.     if (cn.ticking)
  3694.         XtRemoveTimeOut(cn.id);
  3695.     cn.id = XtAppAddTimeOut(appcontext, 500, stream_end, 0);
  3696.     cn.ticking = True;
  3697. }
  3698.  
  3699. /*
  3700.  * Process a VisibilityNotify event, setting the 'visibile' flag in nss.
  3701.  * This will switch the behavior of screen scrolling.
  3702.  */
  3703. void
  3704. PA_VisibilityNotify_action(Widget w unused, XEvent *event unused,
  3705.     String *params unused, Cardinal *num_params unused)
  3706. {
  3707.     XVisibilityEvent *e;
  3708.  
  3709. #if defined(INTERNAL_ACTION_DEBUG) /*[*/
  3710.     action_debug(PA_VisibilityNotify_action, event, params, num_params);
  3711. #endif /*]*/
  3712.     e = (XVisibilityEvent *)event;
  3713.     nss.obscured = (e->state != VisibilityUnobscured);
  3714. }
  3715.  
  3716. /*
  3717.  * Process a GraphicsExpose event, refreshing the screen if we have done
  3718.  * one or more failed XCopyArea calls.
  3719.  */
  3720. void
  3721. PA_GraphicsExpose_action(Widget w unused, XEvent *event unused,
  3722.     String *params unused, Cardinal *num_params unused)
  3723. {
  3724.     int i;
  3725.  
  3726. #if defined(INTERNAL_ACTION_DEBUG) /*[*/
  3727.     action_debug(PA_GraphicsExpose_action, event, params, num_params);
  3728. #endif /*]*/
  3729.  
  3730.     if (nss.copied) {
  3731.         /*
  3732.          * Force a screen redraw.
  3733.          */
  3734.         (void) memset((char *) ss->image, 0,
  3735.                       (maxROWS*maxCOLS) * sizeof(union sp));
  3736.         if (ss->debugging_font)
  3737.             for (i = 0; i < maxROWS*maxCOLS; i++)
  3738.                 ss->image[i].bits.cg = CG_space;
  3739.         ctlr_changed(0, ROWS*COLS);
  3740.         cursor_changed = True;
  3741.  
  3742.         nss.copied = False;
  3743.     }
  3744. }
  3745.  
  3746. /* Display size functions. */
  3747. unsigned
  3748. display_width(void)
  3749. {
  3750.     return XDisplayWidth(display, default_screen);
  3751. }
  3752.  
  3753. unsigned
  3754. display_widthMM(void)
  3755. {
  3756.     return XDisplayWidthMM(display, default_screen);
  3757. }
  3758.  
  3759. unsigned
  3760. display_height(void)
  3761. {
  3762.     return XDisplayHeight(display, default_screen);
  3763. }
  3764.  
  3765. unsigned
  3766. display_heightMM(void)
  3767. {
  3768.     return XDisplayHeightMM(display, default_screen);
  3769. }
  3770.